如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的。Windows操作系统提供了选择(Select)、异步选择(WSAAsyncSelect)、事件选择(WSAEventSelect)、重叠I/O(Overlapped I/O)和完成端口(Completion Port)共五种I/O模型。每一种模型均适用于一种特定的应用场景。程序员应该对自己的应用需求非常明确,而且综合考虑到程序的扩展性和可移植性等因素,作出自己的选择。
我会以一个回应反射式服务器(与《Windows网络编程》第八章一样)来介绍这五种I/O模型。 我们假设客户端的代码如下(为代码直观,省去所有错误检查,以下同):
1 #include <WINSOCK2.H> 2 #include <stdio.h> 3 #define SERVER_ADDRESS "137.117.2.148" 4 #define PORT 5150 5 #define MSGSIZE 1024 6 #pragma comment(lib, "ws2_32.lib") 7 8 int main() 9 { 10 //用作WSAStartup()函数的第二个参数,接收Windows Sockets实现的细节。 11 WSADATA wsaData; 12 //用来与服务器socket进行通信的客户端socket。 13 SOCKET sClient; 14 //用来设置服务器的地址信息。 15 SOCKADDR_IN server; 16 char szMessage[MSGSIZE]; 17 int ret; 18 //第一步:初始化Winsock库 19 WSAStartup(0x0202, &wsaData); 20 //第二步:创建用来与服务器进行通信的客户端 21 sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 22 //第三步:将服务器端的地址信息保存入SOCKADDR_IN类型的变量sever中 23 memset(&server, 0, sizeof(SOCKADDR_IN)); 24 server.sin_family = AF_INET; 25 server.sin_addr.S_un.S_addr = inet_addr(SERVER_ADDRESS); 26 server.sin_port = htons(PORT); 27 //第四步:通过connect函数向服务器发起连接。 28 connect(sClient, (struct sockaddr *)&server, sizeof(SOCKADDR_IN)); 29 while (TRUE) 30 { 31 //连接服务器成功后,客户端控制台窗口将显示Send: 32 printf("Send:"); 33 //将用户输入的内容保存到szMessage中 34 gets(szMessage); 35 //发送消息将szMessage中的内容通过sClient发往服务器 36 send(sClient, szMessage, strlen(szMessage), 0); 37 //将接收到的内容放入szMessage中 38 ret = recv(sClient, szMessage, MSGSIZE, 0); 39 szMessage[ret] = '