windows下基于异步通知IO模型的回声服务器和客户端的实现
1. 利用异步io通知模型实现回声服务器端
#include <stdio.h> #include <string.h> #include <winsock2.h> #define BUF_SIZE 100 void CompressSockets(SOCKET hSockArr[], int idx, int total); void CompressEvents(WSAEVENT hEventArr[], int idx, int total); void ErrorHandling(char *msg); int main(int argc, char *argv[]) { WSADATA wsaData; SOCKET hServSock, hClntSock; SOCKADDR_IN servAdr, clntAdr; SOCKET hSockArr[WSA_MAXIMUM_WAIT_EVENTS]; WSAEVENT hEventArr[WSA_MAXIMUM_WAIT_EVENTS]; WSAEVENT newEvent; WSANETWORKEVENTS netEvents; //保存发生的事件类型信息和错误信息的结构体变量 int numOfClntSock=0; int strLen, i; int posInfo, startIdx; int clntAdrLen; char msg[BUF_SIZE]; if(argc!=2) { printf("Usage: %s <port>\n", argv[0]); exit(1); } if(WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) ErrorHandling("WSAStartup() error!"); hServSock=socket(PF_INET, SOCK_STREAM, 0); memset(&servAdr, 0, sizeof(servAdr)); servAdr.sin_family=AF_INET; servAdr.sin_addr.s_addr=htonl(INADDR_ANY); servAdr.sin_port=htons(atoi(argv[1])); if(bind(hServSock, (SOCKADDR*) &servAdr, sizeof(servAdr))==SOCKET_ERROR) ErrorHandling("bind() error"); if(listen(hServSock, 5)==SOCKET_ERROR) ErrorHandling("listen() error"); newEvent=WSACreateEvent(); //创建manual_reset模式non-signaled状态的事件对象 /* 指定hServSock套接字句柄为newEvent的监视对象,希望监视的事件类型为: 有新的连接请求 */ if(WSAEventSelect(hServSock, newEvent, FD_ACCEPT)==SOCKET_ERROR) ErrorHandling("WSAEventSelect() error"); hSockArr[numOfClntSock]=hServSock; hEventArr[numOfClntSock]=newEvent; numOfClntSock++; while(1) { /* 验证是否发生事件,成功时返回发生事件的对象信息,只要有一个事件对象的状态变为signaled时就返回 * 可通过以宏的方式申明的WSA_MAXIMUN_WAIT_EVENTS常量得知WSAWaitMulltipleEvents函数可以同时监听的最大事件对象数,该常量为64 * 通过该函数可以得到转为signaled状态的事件对象中的第一个(按数组中的保存顺序)索引值, 返回值减去常量WSA_WAIT_EVENT_0,可以得到 * 转变为signaled状态的事件对象句柄 */ posInfo=WSAWaitForMultipleEvents( numOfClntSock, hEventArr, FALSE, WSA_INFINITE, FALSE); startIdx=posInfo-WSA_WAIT_EVENT_0; /* 获取所有signaled状态的事件对象 */ for(i=startIdx; i<numOfClntSock; i++) { int sigEventIdx= WSAWaitForMultipleEvents(1, &hEventArr[i], TRUE, 0, FALSE); if((sigEventIdx==WSA_WAIT_FAILED || sigEventIdx==WSA_WAIT_TIMEOUT)) { continue; } else { /* 确定与hSockArr[sigEventIdx]套接字句柄相连接的事件对象hEventArr[sigEventIdx]转变为signaled状态的原因, * 发生的事件类型信息和错误信息保存在netEvents结构体变量中 */ sigEventIdx=i; WSAEnumNetworkEvents( hSockArr[sigEventIdx], hEventArr[sigEventIdx], &netEvents); if(netEvents.lNetworkEvents & FD_ACCEPT) { /* 发生连接请求事件 */ if(netEvents.iErrorCode[FD_ACCEPT_BIT]!=0) { puts("Accept Error"); break; } /* 接受连接请求 */ clntAdrLen=sizeof(clntAdr); hClntSock=accept( hSockArr[sigEventIdx], (SOCKADDR*)&clntAdr, &clntAdrLen); /* 指定hClntSock套接字句柄为newEvent的监视对象,希望监视的事件类型为: 有需要接收的数据和断开连接请求 */ newEvent=WSACreateEvent(); WSAEventSelect(hClntSock, newEvent, FD_READ|FD_CLOSE); hEventArr[numOfClntSock]=newEvent; hSockArr[numOfClntSock]=hClntSock; numOfClntSock++; puts("connected new client..."); } if(netEvents.lNetworkEvents & FD_READ) { /* 发生有需要接收的数据事件 */ if(netEvents.iErrorCode[FD_READ_BIT]!=0) { puts("Read Error"); break; } strLen=recv(hSockArr[sigEventIdx], msg, sizeof(msg), 0); send(hSockArr[sigEventIdx], msg, strLen, 0); } if(netEvents.lNetworkEvents & FD_CLOSE) { if(netEvents.iErrorCode[FD_CLOSE_BIT]!=0) { puts("Close Error"); break; } WSACloseEvent(hEventArr[sigEventIdx]); closesocket(hSockArr[sigEventIdx]); numOfClntSock--; CompressSockets(hSockArr, sigEventIdx, numOfClntSock); CompressEvents(hEventArr, sigEventIdx, numOfClntSock); } } } } WSACleanup(); return 0; } void CompressSockets(SOCKET hSockArr[], int idx, int total) { int i; for(i=idx; i<total; i++) hSockArr[i]=hSockArr[i+1]; } void CompressEvents(WSAEVENT hEventArr[], int idx, int total) { int i; for(i=idx; i<total; i++) hEventArr[i]=hEventArr[i+1]; } void ErrorHandling(char *msg) { fputs(msg, stderr); fputc(‘\n‘, stderr); exit(1); }
2.回声客户端实现
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <winsock2.h> #define BUF_SIZE 1024 void ErrorHandling(char *message); int main(int argc, char *argv[]) { WSADATA wsaData; SOCKET hSocket; char message[BUF_SIZE]; int strLen; SOCKADDR_IN servAdr; if(argc!=3) { printf("Usage : %s <IP> <port>\n", argv[0]); exit(1); } if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0) ErrorHandling("WSAStartup() error!"); hSocket=socket(PF_INET, SOCK_STREAM, 0); if(hSocket==INVALID_SOCKET) ErrorHandling("socket() error"); memset(&servAdr, 0, sizeof(servAdr)); servAdr.sin_family=AF_INET; servAdr.sin_addr.s_addr=inet_addr(argv[1]); servAdr.sin_port=htons(atoi(argv[2])); if(connect(hSocket, (SOCKADDR*)&servAdr, sizeof(servAdr))==SOCKET_ERROR) ErrorHandling("connect() error!"); else puts("Connected..........."); while(1) { fputs("Input message(Q to quit): ", stdout); fgets(message, BUF_SIZE, stdin); if(!strcmp(message,"q\n") || !strcmp(message,"Q\n")) break; send(hSocket, message, strlen(message), 0); strLen=recv(hSocket, message, BUF_SIZE-1, 0); message[strLen]=0; printf("Message from server: %s", message); } closesocket(hSocket); WSACleanup(); return 0; } void ErrorHandling(char *message) { fputs(message, stderr); fputc(‘\n‘, stderr); exit(1); }
相关推荐
zhangwentaohh 2020-09-16
leodengzx 2020-06-28
服务器端攻城师 2020-06-26
xcznb 2020-06-26
sapliang 2020-06-12
xasdfg 2020-06-01
bruce 2020-05-17
songjie 2020-02-14
仁鱼 2020-02-12
furongwei 2020-05-10
丁丁爸爸的技术 2020-04-26
xcznb 2020-04-16
服务器端攻城师 2020-02-17
hygbuaa 2020-02-13
SoarFly00 2020-02-11
vanturman 2020-02-10