先复习一下基础。编写winsock程序,需要#include<winsock2.h>这个头文件,这是#pragma comment(lib,"WS2_32.lib")
socket 描述符(套接字句柄)
“在 UNIX 系统中,任何东西都是一个文件。”这句话传达了这样一个理念:在 UNIX 系统中,任何 I/O 操作,都是通过读或写一个文件描述符(File Descriptor,FD)来实现的。
文件描述符只是一个简单的整形数值,代表一个被打开的文件。这里的“文件”并非狭义上的磁盘文件,而是指广义上的文件,它可以代表一个网络上的连接、一个先进先出的队列、一个终端显示屏等。
既然在 UNIX 系统中任何东西都可以抽象为一个文件,通过 Internet 和另外一台机器进行通讯这一典型的 I/O 机制也是基于文件描述符来定义实现的。这个文件描述符即套接字内核对象:int sockfd。在早期的 UNIX/Linux 系统中,可直接调用 read() 和 write() 像操作文件那样对套接字执行类似的读写操作,尽管调用 recv() 和 send() 显得更为专业。
在 Windoze 系统中,内核对象往往交由一个句柄与外部交互,如文件句柄。在很多 WinSock 场合我们习惯使用“套接字句柄”这一称呼:typedef u_int SOCKET。实际上,WinSock 中对于套接字的操作,很大程度上也沿袭了文件操作的规范。例如,在 Winsock 1 规程中,应用程序可以针对套接字句柄调用 ReadFile() 和 WriteFile(),同时指定重叠结构以利用重叠 I/O 模型,到 Winsock 2 中才正式替换为 WSARecv() 和 WSASend(),以专用于套接字操作。
Windows Sockets规范
Sockets 本来是 UNIX 操作系统下流行的一套网络编程接口(API),它是 1983 年在 Berkeley(加州大学伯克利分校)4.2 BSD 操作系统中被首先引入的,因此也被称作“Berkeley Socket API”。
Windows Sockets 是在 Windows 环境下使用的一套网络编程规范,常常简称为 WinSock。在 Winsock 规范中,API 函数集被分为三类:与 BSD Socket 相兼容的基本函数,网络数据信息检索函数和 Windows 专用扩展函数。
Windows Socket 1 规范的核心内容是符合 Berkeley Socket 风格的库函数,例如可以编写基于 select 模型的的跨平台socket 通信库。鉴于后来各大平台都移植支持了 Berkeley Socket 的这一基本 I/O 模型, select 模型可以很好地实现跨平台,但对具体操作系统平台而言并非性能最佳。为了使程序员能充分利用 Windows 消息驱动机制,MS 又定义开发了一组针对 Windows 的扩展库函数,这就是 Windows Socket 2 规范。
Windows Socket 2 规范(Winsock 2.x)提供了基于 Windows 消息机制的 WSAAsyncSelcet 异步 I/O 网络事件通知模型。此外,WinSock 2.x 还提供了基于事件通知的异步 I/O 网络事件通知的 WSAEventSelcet 模型和高效的重叠 I/O 模型。其他操作系统平台也各自实现了更加高效的网络 I/O 管理模型,如 Windoze 的 IOCP 模型、Linux 的 epoll 模型,这些模型基于系统特性和内核机制最大限度地平衡了 I/O 效能(大规模、高并发)。
目前常用的 Winsock 有两个版本:一个是 16 位的 Winsock 1.1,由动态链接库 WINSOCK.DLL 提供支持;另一个是 32 位的 Winsock 2.2,由动态链接库 WSOCK32.DLL 提供支持。
从 Win98/NT4 开始,Windows 引入 WinSock 2,而 WinSock 1 成为 WinSock 2 的功能子集。在 32 位系统下,16 位的 WINSOCK.DLL(Windows Socket 16-bit DLL)为 Non-resident。
ws2_32.dll 和 mswsock.dll 是 WinSock 2 真正的实现者,使用 Dependency Walker 可以看到 wsock32.dll 和 mswsock.dll 都依赖 ws2_32.dll。wsock32.dll 只是映射了 ws2_32.Dll 和 mswsock.dll 这两个函数集的部分内容,并无具体实现。
mswsock.dll 提供了微软特有的 WSA 扩展,包括 AcceptEx/GetAcceptExSockaddrs、ConnectEx/DisconnectEx、TransmitPackets/TransmitFile、WSARecvMsg。其中仅有 AcceptEx/GetAcceptExSockaddrs 和 TransmitFile 这三个函数真正从 mswsock.dll 导出。
如果要求编写符合 Berkeley Socket API 标准的程序,则只需要加载 wsock32.dll 使用 WinSock 1.x 规范(BSD Socket API for Windows)即可。如果要结合 Windows 平台特性编写 WinSock 2.x 的程序,则可加载 ws2_32.dll 和 mswsock.dll 调用 WSA 系列(扩展)函数。加载 WinSock 库是通过 WSAStartup() 来指定的。