生活随笔
收集整理的這篇文章主要介紹了
                                
【网络编程】之九、事件选择WSAEventSelect
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
 
                                
                            
                            
                             WSAEventSelect模型是類似于WSAAsyncSelect模型的另一個有用的異步I/O模型。它允許應用程序在一個或者多個套接字上接收以事件為基礎的網絡事件。 在這里,最主要的差別是在于網絡事件會投遞到一個事件對象句柄。并不是投遞到一個窗口。
 
 我們使用事件模型前,我們的應用程序針對使用的每一個套接字首先要創建一個事件對象:
 
 
 
   [cpp]?view plaincopy     
 WSAEVENT?WSACreateEvent(void);?? 
 
 
下面是注冊自己感興趣的網絡事件類型:
 
 
 
 
 
   [cpp]?view plaincopy     
 int?WSAEventSelect(??? ???_In_??SOCKET?s,????? ???_In_??WSAEVENT?hEventObject,?? ???_In_??long?lNetworkEvents?);?? 
 
 
 當我們用WSACreateEvent創建了事件,他有兩種工作狀態和兩種工作模式:
 
 1、工作狀態:已傳信signaled 和 未傳信nonsignaled。
 
 2、工作模式:人工重置manual reset ?和 ?自動重置auto reset。
 
 
 
 
 剛開始的時候,wsacreateevent是一種未傳信的工作狀態,并且是人工重置的模式來創建一個句柄。 ? 但是我們網絡事件觸發了與一個套接字關聯在一起的事件對象,工作狀態便會從“未傳信”轉變為“已傳信”,由于事件對象是 一種人工重置模式創建的,所以在完成了衣蛾I/O請求處理后,我們的應用程序需要負責將工作狀態改變為“未傳信”。 ? 要這樣我們需要一個函數:
 
 
 
   [cpp]?view plaincopy     
 BOOL?WSAResetEvent(?? ??__in??????????WSAEVENT?hEvent?? );?? 
 
上面這個函數唯一的參數是一個事件句柄,成功返回TRUE,失敗返回FALSE; 
 
 
 
 
 
 當我們完成一個事件對象的處理后,我們要調用WSACloseEvent函數,釋放由事件句柄使用的系統資源:
 
 
 
   [cpp]?view plaincopy     
 BOOL?WSACloseEvent(?? ??__in??????????WSAEVENT?hEvent?? );?? 
 
 
這個函數也是只有一個參數:事件句柄。 成功返回TRUE,失敗返回FALSE; 
 
 
 
 
 
 當我們的一個套接字和一個事件句柄關聯在一起后,應用程序就開始I/O處理,通過WSAWaitForMultipleEvents函數等待網絡事件來出發事件對象句柄的工作狀態。(這個函數用來等待一個或者多個事件對象句柄,并在事先指定的一個或所有句柄進入“已傳信”狀態后,并在超過一個規定的事件周期后立即返回)
 
 
 
   [cpp]?view plaincopy     
 DWORD?WSAWaitForMultipleEvents(?? ??__in??????????DWORD?cEvents,?? ??__in??????????const?WSAEVENT*?lphEvents,?? ??__in??????????BOOL?fWaitAll,?? ??__in??????????DWORD?dwTimeout,?? ??__in??????????BOOL?fAlertable?? );?? 
 
 
來看一個第三個參數fWaitAll。 ?如果這個參數你設為TRUE,那么直有等待lphEvents數組內包含的所有事件對象都進入“已傳信”狀態函數才返回。 ? 如果你設為
FALSE,那么任何一個事件對象進入“已傳信”狀態,函數就會返回。 
 
 
 通常應用程序應將這個參數設為FALSE,一次只為一個套接字事件提供服務。
 
 
 
 
 第四個參數dwTimeout要注意的是盡量避免將超時值設為0, 加入沒有等待處理的事件,WSAWaitForMultipleEvents便會返回WSA_WAIT_TIMEOUT。
 
 你將這個參數設為:WSAINFINITE(永久等待),那么只有當在一個網絡事件傳信了一個事件對象后函數才會返回。
 
 
 
 
 當WSAWaitForMultipleEvents 收到一個事件對象的網絡事件通知,便會返回一個值。指出造成函數返回的事件對象。 ?我們的應用程序就可以引用事件數組中已傳信的事件,并檢索與那個事件對應的套接字,判斷到底是在那個套接字上,發生了什么網絡事件類型。對于事件數組中的事件進行引用時,應該用WSAWaitForMultipleEvents的返回值 減去預定義的WSA_WAIT_EVENT_0得到具體的引用值:
 
 
 
   [cpp]?view plaincopy     
 Index?=?WSAWaitForMultipleEvents(...);?? MyEvent?=?EventArray[Index?-?WSA_WAIT_EVENT_0];?? 
 
 
當我們知道了造成網絡事件的套接字以后,下面可以調用WSAEnumNetworkEvents函數,調查發生了什么類型的網絡事件: 
 
 
 
 
   [cpp]?view plaincopy     
 int?WSAEnumNetworkEvents(?? ??__in??????????SOCKET?s,?? ??__in??????????WSAEVENT?hEventObject,?? ??__out?????????LPWSANETWORKEVENTS?lpNetworkEvents?? );?? 
 
   [cpp]?view plaincopy     
 typedef?struct?_WSANETWORKEVENTS?{?? ??long?lNetworkEvents;??? ??int?iErrorCode[FD_MAX_EVENTS];?? }?WSANETWORKEVENTS,??*LPWSANETWORKEVENTS;?? 
 
 
看下面的實例: 
 
 
 
 
   [cpp]?view plaincopy     
 if?(NetwordEvents.lNetworkEvents?&?FD_READ)?? {?? ????if?(NetworkEvents.iErrorCode[FD_READ_BIT]?!=?0)?? ????{?? ????????printf("FD_READ?failed?with?error?%d\n",?NetworkEvents.iErrorCode[FD_READ_BIT]);?? ????}?? }?? 
 
 
當完成了對WSANETWORKEVENTS結構中的事件的處理之后,我們的應用程序應在所有可用的套接字上繼續等待更多的網絡事件。
 
 
 
 
 下面來看一下使用步驟:
 
 1、建立一個socket。
 
 2、建立一個event。
 
 3、用WSAEventSelect將socket,和event關聯起來。lNetworkEvents可以為 FD_ACCEPT ,FD_READ ,FD_WRITE,FD_CLOSE 等等.
 
 4、等待事件句柄:index = WSAWaitForMultipleEvents(EventTotal,EventArray,FAlSE,100/*WSA_INFINITE*/,FALSE);
 
 5、查詢網絡事件:?int WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents)
 
 6、用lpNetworkEvents.lNetworkEvents & FD_ACCEPT ,lpNetworkEvents.lNetworkEvents & FD_CLOSE找到各個事件處理。
 
 
 
 
  
 
    [cpp]?view plaincopy     
 #include?<WinSock2.h>?? #include?<iostream>?? using?namespace?std;?? ?? #pragma?comment(lib,?"WS2_32.lib")?? ?? int?main()?? {?? ????WSAEVENT?eventArray[1024];?? ????SOCKET?sockArray[1024];?? ????int?nEventTotal?=?0;?? ?? ????WSADATA?wsadata;?? ????WORD?sockVersion?=?MAKEWORD(2,?0);?? ????WSAStartup(sockVersion,?&wsadata);?? ?? ????SOCKET?s??=?socket(AF_INET,?SOCK_STREAM,?IPPROTO_TCP);?? ?? ????sockaddr_in?sin;?? ????sin.sin_family?=?AF_INET;?? ????sin.sin_port?=?htons(8888);?? ????sin.sin_addr.S_un.S_addr?=?INADDR_ANY;?? ????if?(bind(s,?(sockaddr*)&sin,?sizeof(sin))?==?SOCKET_ERROR)?? ????{?? ????????cout?<<?"error"?<<?endl;?? ????????return?0;?? ????}?? ?? ????listen(s,?5);?? ?? ????WSAEVENT?event?=?::WSACreateEvent();?? ????::WSAEventSelect(s,?event,?FD_ACCEPT|FD_CLOSE);?? ?? ????eventArray[nEventTotal]?=?event;?? ????sockArray[nEventTotal]?=?s;?? ? ??nEventTotal++; ?? ????while(TRUE)?? ????{?? ?????????? ????????int?nIndex?=?::WSAWaitForMultipleEvents(nEventTotal,?eventArray,?FALSE,?WSA_INFINITE,?FALSE);?? ?????????? ????????nIndex?=?nIndex?-?WSA_WAIT_EVENT_0;?? ????????for(int?i=nIndex;?i<nEventTotal;?i++)?? ????????{?? ????????????nIndex?=?::WSAWaitForMultipleEvents(1,?&eventArray[i],?TRUE,?1000,?FALSE);?? ????????????if(nIndex?==?WSA_WAIT_FAILED?||?nIndex?==?WSA_WAIT_TIMEOUT)?? ????????????{?? ????????????????continue;?? ????????????}?? ????????????else?? ????????????{?? ?????????????????? ????????????????WSANETWORKEVENTS?event;?? ????????????????::WSAEnumNetworkEvents(sockArray[i],?eventArray[i],?&event);?? ????????????????if(event.lNetworkEvents?&?FD_ACCEPT)?????????????????? ????????????????{?? ????????????????????if(event.iErrorCode[FD_ACCEPT_BIT]?==?0)?? ????????????????????{?? ????????????????????????if(nEventTotal?>?WSA_MAXIMUM_WAIT_EVENTS)?? ????????????????????????{?? ????????????????????????????cout?<<?"?Too?many?connections!?"?<<?endl;?? ????????????????????????????continue;?? ????????????????????????}?? ????????????????????????SOCKET?sNew?=?accept(sockArray[i],?NULL,?NULL);?? ????????????????????????WSAEVENT?event?=?::WSACreateEvent();?? ????????????????????????::WSAEventSelect(sNew,?event,?FD_READ|FD_CLOSE|FD_WRITE);?? ?????????????????????????? ????????????????????????eventArray[nEventTotal]?=?event;?? ????????????????????????sockArray[nEventTotal]?=?sNew;?????? ????????????????????????nEventTotal++;?? ????????????????????}?? ????????????????}?? ????????????????else?if(event.lNetworkEvents?&?FD_READ)?????????????? ????????????????{?? ????????????????????if(event.iErrorCode[FD_READ_BIT]?==?0)?? ????????????????????{?? ????????????????????????char?szText[256];?? ????????????????????????int?nRecv?=?::recv(sockArray[i],?szText,?256,?0);?? ????????????????????????if(nRecv?>?0)?????????????????? ????????????????????????{?? ????????????????????????????szText[nRecv]?=?0;?? ????????????????????????????cout?<<?"接收到數據:"?<<?szText?<<?endl;?? ????????????????????????}?? ????????????????????}?? ????????????????}?? ????????????????else?if(event.lNetworkEvents?&?FD_CLOSE)?????????? ????????????????{?? ????????????????????if(event.iErrorCode[FD_CLOSE_BIT]?==?0)?? ????????????????????{?? ????????????????????????::closesocket(sockArray[i]);?? ????????????????????????for(int?j=i;?j<nEventTotal-1;?j++)?? ????????????????????????{?? ????????????????????????????eventArray[j]?=?eventArray[j+1];?? ????????????????????????????sockArray[j]?=?sockArray[j+1];?????? ????????????????????????}?? ????????????????????????nEventTotal--;?? ????????????????????????i--;?? ????????????????????}?? ????????????????}?? ????????????????else?if(event.lNetworkEvents?&?FD_WRITE)?????????? ????????????????{?? ????????????????}?? ????????????}?? ????????}?? ????}?? ?? ????return?0;?? }??    
 
 
                  2012/9/2
  jofranks 于南昌
                            總結
                            
                                以上是生活随笔為你收集整理的【网络编程】之九、事件选择WSAEventSelect的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                            
                                如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。