套接字I/O模型(WSAEventSelect模型)詳解

WSAEventSelect模型類似WSAAsynSelect模型,但最主要的區別是網絡事件發生時會被髮送到一個事件對象句柄,而不是發送到一個窗口。這樣可能更加的好,對於服務器端的程序來說。

使用步驟如下:

a、 創建事件對象來接收網絡事件:

WSAEVENT WSACreateEvent( void );

該函數的返回值爲一個事件對象句柄,它具有兩種工作狀態:已傳信(signaled)和未傳信(nonsignaled)以及兩種工作模式:人工重設(manual reset)和自動重設(auto reset)。默認未未傳信的工作狀態和人工重設模式。

 

b、將事件對象與套接字關聯,同時註冊事件,使事件對象的工作狀態從未傳信轉變未已傳信。

int WSAEventSelect( SOCKET s,WSAEVENT hEventObject,long lNetworkEvents );
s爲套接字
hEventObject爲剛纔創建的事件對象句柄

lNetworkEvents爲掩碼,定義如上面所述

 

c、I/O處理後,設置事件對象爲未傳信
BOOL WSAResetEvent( WSAEVENT hEvent );
Hevent爲事件對象

成功返回TRUE,失敗返回FALSE。

 

d、等待網絡事件來觸發事件句柄的工作狀態:

DWORD WSAWaitForMultipleEvents( DWORD cEvents,const WSAEVENT FAR * lphEvents, BOOL fWaitAll,DWORD dwTimeout, BOOL fAlertable );
lpEvent爲事件句柄數組的指針
cEvent爲爲事件句柄的數目,其最大值爲WSA_MAXIMUM_WAIT_EVENTS
fWaitAll指定等待類型:TRUE:當lphEvent數組重所有事件對象同時有信號時返回;
FALSE:任一事件有信號就返回。
dwTimeout爲等待超時(毫秒)

fAlertable爲指定函數返回時是否執行完成例程

 

nIndex=WSAWaitForMultipleEvents(…);

MyEvent=EventArray[Index- WSA_WAIT_EVENT_0];

 

 

事 件選擇模型也比較簡單,實現起來也不是太複雜,它的基本思想是將每個套接字都和一個WSAEVENT對象對應起來,並且在關聯的時候指定需要關注的哪些網 絡事件。一旦在某個套接字上發生了我們關注的事件(FD_READ和FD_CLOSE),與之相關聯的WSAEVENT對象被Signaled。程序定義 了兩個全局數組,一個套接字數組,一個WSAEVENT對象數組,其大小都是MAXIMUM_WAIT_OBJECTS(64),兩個數組中的元素一一對 應。
同樣的,這裏的程序沒有考慮兩個問題,一是不能無條件的調用accept,因爲我們支持的併發連接數有限。解決方法是將套接字按 MAXIMUM_WAIT_OBJECTS分組,每MAXIMUM_WAIT_OBJECTS個套接字一組,每一組分配一個工作者線程;或者採用 WSAAccept代替accept,並回調自己定義的Condition Function。第二個問題是沒有對連接數爲0的情形做特殊處理,程序在連接數爲0的時候CPU佔用率爲100%。

 

1 SOCKET       Socket[WSA_MAXIMUM_WAIT_EVENTS];
2 WSAEVENT    Event[WSA_MAXIMUM_WAIT_EVENTS];
3 SOCKET     Accept, Listen;
5 DWORD      EventTotal = 0;
6 DWORD      Index;
7
8 //Set up a TCP socket for listening on port 5150
9 Listen = socket(PF_INET,SOCK_STREAM,0);
10
11 InternetAddr.sin_family      = AF_INET;
12 InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
13 InternetAddr.sin_port        = htons(5150);
14
15 bind(Listen,(PSOCKADDR) &InternetAddr,sizeof(InternetAddr));
16
17 NewEvent = WSACreateEvent();
18
19 WSAEventSelect(Listen,NewEvnet,FD_ACCEPT|FD_CLOSE);
20
21 listen(Listen,5);
22
23 Socket[EventTotal] = Listen;
24 Event[EventTotal] = NewEvent;
25 EventTotal++;
26
27 while (TRUE)
28 {
29     //Wait for network events on all sockets
30      Index = WSAWaitForMultipleEvents(EventTotal,EventArray,FALSE,WSA_INFINITE,FALSE);
31
32     WSAEnumNewWorkEvents(SocketArray[Index-WSA_WAIT_EVENT_0],
33          EventArray[Index-WSA_WAIT_EVENT_0],
34         &NetworkEvents);
35     //Check for FD_ACCEPT messages
36     if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
37      {
38         if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] !=0)
39          {
40             //Error
41             break;
42          }
43         //Accept a new connection and add it to the socket and event lists
44         Accept = accept(SocketArray[Index-WSA_WAIT_EVENT_0],NULL,NULL);
45
46         //We cannot process more than WSA_MAXIMUM_WAIT_EVENTS sockets ,
47         //so close the accepted socket
48         if (EventTotal > WSA_MAXIMUM_WAIT_EVENTS)
49          {
50              printf("..");
51              closesocket (Accept);
52             break;
53          }
54          NewEvent = WSACreateEvent();
55
56         WSAEventSelect(Accept,NewEvent,FD_READ|FD_WRITE|FD_CLOSE);
57
58          Event[EventTotal] = NewEvent;
59         Socket[EventTotal]= Accept;
60          EventTotal++;
61          prinrt("Socket %d connect/n",Accept);
62      }
63     //Process FD_READ notification
64     if (NetworkEvents.lNetwoAD)rkEvents & FD_RE
65      {
66         if (NetworkEvents.iErrorCode[FD_READ_BIT !=0])
67          {
68             //Error
69             break;
70          }
71
72         //Read data from the socket
73         recv(Socket[Index-WSA_WAIT_EVENT_0],buffer,sizeof(buffer),0);
74      }
75     //process FD_WRITE notitication
76     if (NetworkEvents.lNetworkEvents & FD_WRITE)
77      {
78         if (NetworkEvents.iErrorCode[FD_WRITE_BIT] !=0)
79          {
80             //Error
81             break;
82          }
83         send(Socket[Index-WSA_WAIT_EVENT_0],buffer,sizeof(buffer),0);
84      }
85     if (NetworkEvents.lNetworkEvents & FD_CLOSE)
86      {
87         if(NetworkEvents.iErrorCode[FD_CLOSE_BIT] !=0)
88          {
89             //Error
90             break;
91          }
92          closesocket (Socket[Index-WSA_WAIT_EVENT_0]);
93         //Remove socket and associated event from the Socket and Event arrays and
94         //decrement eventTotal
95          CompressArrays(Event,Socket,& EventTotal);
96      }
97 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章