windows下基于异步通知IO模型的回声服务器和客户端的实现
Posted chenweilin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了windows下基于异步通知IO模型的回声服务器和客户端的实现相关的知识,希望对你有一定的参考价值。
1. 利用异步io通知模型实现回声服务器端
1 #include <stdio.h> 2 #include <string.h> 3 #include <winsock2.h> 4 5 #define BUF_SIZE 100 6 7 void CompressSockets(SOCKET hSockArr[], int idx, int total); 8 void CompressEvents(WSAEVENT hEventArr[], int idx, int total); 9 void ErrorHandling(char *msg); 10 11 int main(int argc, char *argv[]) 12 { 13 WSADATA wsaData; 14 SOCKET hServSock, hClntSock; 15 SOCKADDR_IN servAdr, clntAdr; 16 17 SOCKET hSockArr[WSA_MAXIMUM_WAIT_EVENTS]; 18 WSAEVENT hEventArr[WSA_MAXIMUM_WAIT_EVENTS]; 19 WSAEVENT newEvent; 20 WSANETWORKEVENTS netEvents; //保存发生的事件类型信息和错误信息的结构体变量 21 22 int numOfClntSock=0; 23 int strLen, i; 24 int posInfo, startIdx; 25 int clntAdrLen; 26 char msg[BUF_SIZE]; 27 28 if(argc!=2) { 29 printf("Usage: %s <port> ", argv[0]); 30 exit(1); 31 } 32 if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) 33 ErrorHandling("WSAStartup() error!"); 34 35 hServSock=socket(PF_INET, SOCK_STREAM, 0); 36 memset(&servAdr, 0, sizeof(servAdr)); 37 servAdr.sin_family=AF_INET; 38 servAdr.sin_addr.s_addr=htonl(INADDR_ANY); 39 servAdr.sin_port=htons(atoi(argv[1])); 40 41 if(bind(hServSock, (SOCKADDR*) &servAdr, sizeof(servAdr))==SOCKET_ERROR) 42 ErrorHandling("bind() error"); 43 44 if(listen(hServSock, 5)==SOCKET_ERROR) 45 ErrorHandling("listen() error"); 46 47 newEvent=WSACreateEvent(); //创建manual_reset模式non-signaled状态的事件对象 48 /* 指定hServSock套接字句柄为newEvent的监视对象,希望监视的事件类型为: 有新的连接请求 */ 49 if(WSAEventSelect(hServSock, newEvent, FD_ACCEPT)==SOCKET_ERROR) 50 ErrorHandling("WSAEventSelect() error"); 51 52 hSockArr[numOfClntSock]=hServSock; 53 hEventArr[numOfClntSock]=newEvent; 54 numOfClntSock++; 55 56 while(1) 57 { 58 /* 验证是否发生事件,成功时返回发生事件的对象信息,只要有一个事件对象的状态变为signaled时就返回 59 * 可通过以宏的方式申明的WSA_MAXIMUN_WAIT_EVENTS常量得知WSAWaitMulltipleEvents函数可以同时监听的最大事件对象数,该常量为64 60 * 通过该函数可以得到转为signaled状态的事件对象中的第一个(按数组中的保存顺序)索引值, 返回值减去常量WSA_WAIT_EVENT_0,可以得到 61 * 转变为signaled状态的事件对象句柄 62 */ 63 posInfo=WSAWaitForMultipleEvents( 64 numOfClntSock, hEventArr, FALSE, WSA_INFINITE, FALSE); 65 startIdx=posInfo-WSA_WAIT_EVENT_0; 66 /* 获取所有signaled状态的事件对象 */ 67 for(i=startIdx; i<numOfClntSock; i++) 68 { 69 int sigEventIdx= 70 WSAWaitForMultipleEvents(1, &hEventArr[i], TRUE, 0, FALSE); 71 if((sigEventIdx==WSA_WAIT_FAILED || sigEventIdx==WSA_WAIT_TIMEOUT)) 72 { 73 continue; 74 } 75 else 76 { /* 确定与hSockArr[sigEventIdx]套接字句柄相连接的事件对象hEventArr[sigEventIdx]转变为signaled状态的原因, 77 * 发生的事件类型信息和错误信息保存在netEvents结构体变量中 78 */ 79 sigEventIdx=i; 80 WSAEnumNetworkEvents( 81 hSockArr[sigEventIdx], hEventArr[sigEventIdx], &netEvents); 82 if(netEvents.lNetworkEvents & FD_ACCEPT) 83 { /* 发生连接请求事件 */ 84 if(netEvents.iErrorCode[FD_ACCEPT_BIT]!=0) 85 { 86 puts("Accept Error"); 87 break; 88 } 89 /* 接受连接请求 */ 90 clntAdrLen=sizeof(clntAdr); 91 hClntSock=accept( 92 hSockArr[sigEventIdx], (SOCKADDR*)&clntAdr, &clntAdrLen); 93 /* 指定hClntSock套接字句柄为newEvent的监视对象,希望监视的事件类型为: 有需要接收的数据和断开连接请求 */ 94 newEvent=WSACreateEvent(); 95 WSAEventSelect(hClntSock, newEvent, FD_READ|FD_CLOSE); 96 97 hEventArr[numOfClntSock]=newEvent; 98 hSockArr[numOfClntSock]=hClntSock; 99 numOfClntSock++; 100 puts("connected new client..."); 101 } 102 103 if(netEvents.lNetworkEvents & FD_READ) 104 { /* 发生有需要接收的数据事件 */ 105 if(netEvents.iErrorCode[FD_READ_BIT]!=0) 106 { 107 puts("Read Error"); 108 break; 109 } 110 strLen=recv(hSockArr[sigEventIdx], msg, sizeof(msg), 0); 111 send(hSockArr[sigEventIdx], msg, strLen, 0); 112 } 113 114 if(netEvents.lNetworkEvents & FD_CLOSE) 115 { 116 if(netEvents.iErrorCode[FD_CLOSE_BIT]!=0) 117 { 118 puts("Close Error"); 119 break; 120 } 121 WSACloseEvent(hEventArr[sigEventIdx]); 122 closesocket(hSockArr[sigEventIdx]); 123 124 numOfClntSock--; 125 CompressSockets(hSockArr, sigEventIdx, numOfClntSock); 126 CompressEvents(hEventArr, sigEventIdx, numOfClntSock); 127 } 128 } 129 } 130 } 131 WSACleanup(); 132 return 0; 133 } 134 135 void CompressSockets(SOCKET hSockArr[], int idx, int total) 136 { 137 int i; 138 for(i=idx; i<total; i++) 139 hSockArr[i]=hSockArr[i+1]; 140 } 141 void CompressEvents(WSAEVENT hEventArr[], int idx, int total) 142 { 143 int i; 144 for(i=idx; i<total; i++) 145 hEventArr[i]=hEventArr[i+1]; 146 } 147 void ErrorHandling(char *msg) 148 { 149 fputs(msg, stderr); 150 fputc(‘ ‘, stderr); 151 exit(1); 152 }
2.回声客户端实现
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <winsock2.h> 5 6 #define BUF_SIZE 1024 7 void ErrorHandling(char *message); 8 9 int main(int argc, char *argv[]) 10 { 11 WSADATA wsaData; 12 SOCKET hSocket; 13 char message[BUF_SIZE]; 14 int strLen; 15 SOCKADDR_IN servAdr; 16 17 if(argc!=3) { 18 printf("Usage : %s <IP> <port> ", argv[0]); 19 exit(1); 20 } 21 22 if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0) 23 ErrorHandling("WSAStartup() error!"); 24 25 hSocket=socket(PF_INET, SOCK_STREAM, 0); 26 if(hSocket==INVALID_SOCKET) 27 ErrorHandling("socket() error"); 28 29 memset(&servAdr, 0, sizeof(servAdr)); 30 servAdr.sin_family=AF_INET; 31 servAdr.sin_addr.s_addr=inet_addr(argv[1]); 32 servAdr.sin_port=htons(atoi(argv[2])); 33 34 if(connect(hSocket, (SOCKADDR*)&servAdr, sizeof(servAdr))==SOCKET_ERROR) 35 ErrorHandling("connect() error!"); 36 else 37 puts("Connected..........."); 38 39 while(1) 40 { 41 fputs("Input message(Q to quit): ", stdout); 42 fgets(message, BUF_SIZE, stdin); 43 44 if(!strcmp(message,"q ") || !strcmp(message,"Q ")) 45 break; 46 47 send(hSocket, message, strlen(message), 0); 48 strLen=recv(hSocket, message, BUF_SIZE-1, 0); 49 message[strLen]=0; 50 printf("Message from server: %s", message); 51 } 52 53 closesocket(hSocket); 54 WSACleanup(); 55 return 0; 56 } 57 58 void ErrorHandling(char *message) 59 { 60 fputs(message, stderr); 61 fputc(‘ ‘, stderr); 62 exit(1); 63 }
以上是关于windows下基于异步通知IO模型的回声服务器和客户端的实现的主要内容,如果未能解决你的问题,请参考以下文章
windows下的IO模型之异步选择(WSAAsyncSelect)模型