今天我又學習了一種新的套接字I/O模型------WSAEventSelect,他與WSAAsyncSelect一樣也是一種異步事件通知模型,不同的是WSAAsyncSelect是與窗口句柄關聯在一起的,必須要要窗口才行,而WSAEventSelect是與事件對象關聯的。這個模型的基本思路是爲感興趣的一組網絡事件創建一個事件對象,再調用WSAEventSelect函數將網絡事件和事件對象關聯起來。當網絡事件發生時,winsock使響應的事件對象受信,在事件對象上等待的函數就會立即返回。之後調用WSAEnumNetworkEvents函數便可獲得到底發生了什麼網絡事件(FD_READ/FD_ACCEPT/FD_CLOSE等等)。
用到的函數有:
WSACreateEvent 、WSAEventSelect、WSAWaitForMultipleEvents、WSAEnumNetworkEvents
等,這裏只詳細介紹下WSAWaitForMultipleEvents函數
關聯了事件對象後就可以用WSAWaitForMultipleEvents函數在一個或多個事件對象上等待了,當所等待的事件對象受信或者指定的時間過去了,此函數返回。
WSAWaitForMultipleEvents(
DWORD cEVents; //指定下面lpEvents所指的數組中事件對象句柄的個數
const WSAEVENT* lpEvents; //指向一個事件對象句柄的數組
BOOL fWaitAll; //指定是否等待所有的事件對象都變成受信狀態(爲TRUE:是;FALSE:否)
DWORD dwTimeout; //指定要等待的時間,可以爲WSA_INFINITE
BOOL fAlertable; //設爲FALSE
);
函數最多可以支持WSA_MAXIMUM_WAIT_EVENTS個對象,他的大小是64.該函數會等待網絡事件的發生,如果過了指定了時間(dwTimeOut)則返回WSA_WAIT_TIMEOUT,如果在規定的時間內有事件發生,則返回該事件對象的索引(注意:在程序中要想得到發生的事件的真正索引需得用返回值減去WSA_WAIT_EVENT_0),調用失敗返回WSA_WAIT_FAILED.如果將參數fWaitAll設置成false如果有多個網絡事件發生該函數也只返回一個事件對象索引,並且該事件是在事件句柄數組中最前面的一個.解決方法是循環調用該函數處理後面的受信事件.
該函數的第一個參數是後面事件對象句柄數組的大小,第二個是個事件對象句柄數組,最後一個設置成false即可.
一旦事件對象受信那麼找到與之對應的套接字,然後調用 int WSAEnumNetWorkEvent(SOCKET s, WSAEVENT hEventHandle, LPWSANETWORKEVENTS *LPWSANETWORKEVENTS)可以查看發生的網絡事件,第一個參數和相應的網絡事件標識做與運算就可.第二參數是返回的錯誤信息。
下面給分別給出用WSAEventSelect模型寫出的TCP/UDP服務器例子.
TCP例子:
TCP例子就是在監聽套接字上關聯一個事件對象以及FD_ACCEPT|FD_CLOSE網絡事件。
下面是UDP的例子:
UDP例子就是在一個普通套接字上關聯一個事件對象以及FD_READ網絡事件。