標籤:lis 事件通知 table 控制代碼 定義 轉變 lap recv 引用
1.事件選擇模型:和非同步選擇模型類似的是,它也允許應用程式在一個或多個通訊端上,接收以事件為基礎的網路事件通知。對於非同步選擇模型採用的網路事件來說,它們均可原封不動地移植到事件選擇模型。事件選擇模型和非同步選擇模型最主要的差別在於網路事件會投遞至一個事件物件控點,而非投遞至一個視窗常式。
2.建立事件對象:事件選擇模型要求應用程式針對打算使用事件選擇模型的每一個通訊端,首先建立一個事件對象。建立方法是調用WSACreateEvent函數,它的定義如下:WSAEVENT WSACreateEvent(void);
3.綁定事件對象與通訊端:
int WSAEventSelect(
SOCKET s,
WSAEvent hEventObject,
long lNetworkEvents//網路事件,就是非同步選擇中的網路事件,用法完全相同
);
對於事件來說,他有兩種類型,自動事件和人工事件。有兩種狀態,未觸發狀態和觸發狀態。使用WSACreateEvent函數建立的事件預設為人工事件且處於未觸發狀態。隨著網路事件觸發了與一個通訊端關聯在一起的事件對象,工作狀態便會從未觸發狀態轉變成觸發狀態。由於事件對象是在一種人工重設模式中建立的,所以在完成了一個I/O請求的處理之後,我們的應用程式需要負責將工作
狀態觸發狀態更改未觸發狀態。
4.重設事件為未觸發狀態:
BOOL WSAResetEvent(WSAEVENT hEvent);
該函數的功能就是把時間從觸發狀態重設為未觸發狀態
5.關閉事件對象,釋放其所佔用的核心資源:
BOOL WSACloseEvent(WSAEVENT hEvent);
6.監視事件對象的狀態:
DWORD WSAWaitForMultipleEvents(
DWORD cEvents;//事件對象數組中事件的數目
const WSAEVENT FAR* lphEvents,//事件對象數組
BOOL fWaitAll,//該參數指明了是否要等到所有事件對象變為觸發狀態函數才返回
DWORD dwTimeout,//逾時,毫秒為單位超過規定的時間,函數就會立即返回,即使由fWaitAll參數規定的條件尚未滿足也如此
BOOL fAlertable//忽略,置為FALSE
);
參數:
要注意的是,WSAWaitForMultipleEvents只能支援由WSA_MAXIMUM_WAIT_EVENTS對象規定的一個最大值,在此定義成6 4個。因此,針對發出WSAWaitForMultipleEvents調用的每個線程,該I/O模型一次最多都只能支援6 4個通訊端。假如想讓這個模型同時管理不止64個通訊端,必須建立額外的工作者線程,以便等待更多的事件對象。fWaitAll 參數指定了指明了是否要等到所有事件對象變為觸發狀態函數才返回。若設為TRUE,那麼只有等lphEvents數組內包含的所有事件對象都已進入觸發狀態,函數才會返回;但若設為FALSE,任何一個事件對象進入觸發狀態,函數就會返回。就後一種情況來說,傳回值指出了到底是哪個事件對象造成了函數的返回。通常,應用程式應將該參數設為FALSE,通常,dwTimeout被置為0.
一次只為一個通訊端事件提供服務
函數解釋:
一個通訊端同一個事件物件控點關聯在一起後,應用程式便可開始I/O處理;方法是等待網路事件觸發事件物件控點的工作狀態。WSAWaitForMultipleEvents函數的設計宗旨便是用來等待一個或多個事件物件控點,並在事先指定的一個或所有事件對象進入觸發狀態後,
或在超過了一個規定的時間周期後,立即返回。
7.確定網路事件發生的通訊端:若WSAWaitForMultipleEvents收到一個事件對象的網路事件通知,便會返回一個值,指出造成函數返回的事件對象。這樣一來,我們的應用程式便可引用事件數目組中已傳信的事件,並檢索與那個事件對應的通訊端,判斷到底是在哪個通訊端上,發生了什麼網路事件類型。對事件數目組中的事件進行引用時,應該用WSAWaitForMultipleEvents的傳回值,減去預定義值WSA_WAIT_EVENT_0,得到具體的引用值(即索引位置)。
Index=WSAWaitForMultipleEvents(...);
myEvent=EventArray[Index-WSA_WAIT_EVENT_0];
7.調查發生的網路事件類型:
int WSAEnumNetworkEvents(
SOCKET s,
WSAEVENT hEventObjects,//參數可選,對應於打算重設的事件對象,即設定事件為未觸發狀態。和WSAtResetEvent函數功能相同
LPWSANETWORKEVENTS lpNetworkEvents//用來接受發生的網路事件類型以及可能出現的任何錯誤碼
);
該函數中的第四個參數用來接收發生的網路事件類型
8.WSANETWORKEVENTS結構:
tydef struct _WSANETWORKEVENTS
{
long lNetworkEvents;//網路事件類型
long iErrorCode[FD_MAX_EVENTS];//錯誤碼
}WSANETWORKEVENTS,FAR* LPWSANETWORKEVENTS;
iErrorCode參數指定的是一個錯誤碼數組,同lNetworkEvents中的事件關聯在一起。iErrorCode針對每個網路事件類型,都存在著一個特殊的事件索引,名字與事件類型的名字類似,只是要在事件名字後面添加一個“ _BIT”尾碼字串即可.
範例程式碼:
1 SOCKET Socket[WSA_MAXIMUM_WAIT_EVENTS];//64 2 WSAEVENT event[WSA_MAXIMUM_WAIT_EVENTS]; 3 SOCKET accept,listen; 4 DWORD eventTotal=0; 5 DWORD index; 6 7 //建立通訊端 8 listen=socket(...); 9 10 //綁定本地地址11 bind(...);12 13 //建立事件對象14 WSAEVENT newEvent;15 newEvent=WSACreateEvent();16 17 //註冊網路事件18 WSAEventSelect(listen,newEvent,FD_ACCEPT|FD_CLOSE);19 20 Socket[eventTotal]=listen;21 event[eventTotal]=newEventl;22 eventTotal++;23 24 25 while(1)26 {27 //等待事件觸發狀態28 index=WSAWaitForMultipleEvents(eventTotal,event,FALSE,WSA_INFINITE,FALSE);29 30 //查看發生的網路事件類型,確定發生網路事件的通訊端31 WSANETWORKEVENTS networkEvents;32 WSAEnumNetworkEvents(Socket[index-WSA_WAIT_EVENT_0],event[index-WSA_WAIT_EVENT_0],&networkEvents);33 34 //確定發生的網路事件類型35 if(networkEvents.lNetworkEvents&FD_ACCEPT)36 {37 if(networkEvents.iErrorCode[FD_ACCEPT_BIT]!=0)38 {39 printf("FD_ACCEPT failed with error %d\n",networkEvents.iErrorCode[FD_ACCEPT_BIT]);40 break;41 }42 43 //FD_ACCEPT事件發生後,則進行後續處理44 accept=accept(Socket[index_WSA_WAIT_EVENT_0],NULL,NULL);45 46 //查看事件對象的數目47 if(eventTotal>WSA_MAXIMUM_WAIT_EVENTS)48 {49 printf("too many connections\n");50 closesocket(accept);51 break;52 }53 54 //再次建立事件,再次進行上述操作,進行迴圈55 newEvent=WSACreateEvent();56 57 WSAEventSelect(listen, newEvent, FD_READ|FD_WRITE | FD_CLOSE);58 59 event[eventTotal]=newEvent;60 Socket[eventTotal]=accept;61 eventTotal++;62 printf("socket %d connected\n",accept);63 }64 65 //FD_READ事件的處理66 //雷同於FD_ACCEPT網路事件的處理67 if(networkEvents.lNetworkEvents&FD_READ)68 {69 if(networkEvents.iErrorCode[FD_READ_BIT]!=0)70 {71 printf("FD_READ failed with error %d\n",networkEvents.iErrorCode[FD_READ_BIT]);72 break;73 }74 //讀取資料75 recv(Socket[index-WSA_WAIT_EVENT_0],buf,sizeof(buf),0);76 }77 78 //接下來其他網路事件的處理同上,但是需要注意一點,事件選擇模型是基於視窗程序的,並且需要訊息發送,只是這部分代碼為給出而已79 80 }81 82 83 84
View Code
三.Windows I/O模型之事件選擇(WSAEventSelect )模型