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模型的回声服务器和客户端的实现的主要内容,如果未能解决你的问题,请参考以下文章

IOCP模型EPOLL模型的比较以及游戏服务器端的一些建议

windows下的IO模型之异步选择(WSAAsyncSelect)模型

linux五种IO模型与事件驱动模型

windows下的IO模型之事件选择(WSAEventSelect)模型

网络IO模型-异步选择

HttpServer: 基于IOCP模型且集成Openssl的轻量级高性能web服务器