socket模型使歸納(EventSelect—>HPR_WaitForMultipleObjects—>EnumNetworkEvents樣本)

來源:互聯網
上載者:User

共有五種類型的通訊端I/O模型,可讓Winsock應用程式對I/O進行管理,它們包括:select(選擇)、WSAAsyncSelect(非同步選擇)、WSAEventSelect(事件選擇)、overlapped(重疊)以及completion port(完成連接埠) 

1.select 
最初設計該模型,主要是面向某些使用Unix作業系統的電腦.使用大概原理設定一個集合,通過一個宏的定義來查詢集合類的通訊端可否使用。做個連接埠掃描用這個還是比較開心的。 

2.WSAAsyncSelect 
模仿WINDOWS訊息機制來實現,使用起來很方便。個人比較喜歡。MFC中的CSOCKET也採用了這個模型。 
相關函數: 
int WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent); 
lEvent表示一個掩碼組合,比如FD_CONNECT|FD_READ 

LREWULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 
wParam: 發生了一個網路事件的通訊端 
lParam: (低位)指定了已經發生的網路事件WSAGETSELECTEVENT (高位)包含了可能出現的任何錯誤碼 用WSAGETSELECTERROR擷取 

大概使用架構如下: 
建立通訊端,使用WSAAsyncSelect進行通訊端和事件綁定,在回呼函數中寫清訊息響應 

#define WM_SOCKET WM_USER+1 
int WINAPI WinMain(HINSTANCE hINstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 

SOCKET Listen; 
HWND Window; 
//Create a window and assign the winproc 
//Start Winsock and create a socket 
WSAStartup(...); 
Listen = Socket(); 
bind(...); 
WSAAsyscSelect(Listen, Window, WM_SOCKET, FD_ACCEPT | FD_CLOSE); 
listen(Listen, 5); 

BOOL CALLBACK WinProc(HWND hDlg, WORD wMsg, WORD wParam, DWORD lParam) 

SOCKET Accept; 
switch(wMsg) 

case WM_SOCKET: 
//whether an error occurred on the socket by using the WSAGETSELECTERROR() macro 
if(WSAGETSELECTERROR(lParam)) 

closesocket... 

//what event occurred on the socket 
switch( WSAGETSELECTEVENT(lParam) ) 

case FD_ACCEPT: 
case FD_READ: 
case FD_WRITE: 


FD_WRITE說明:三種條件下才會發出 
使用connect WSAConnect,一個通訊端首次建立串連 
使用accept WSAAccept,通訊端被接受以後 
若send WSASend sendto WSASendTo操作失敗,返回WSAEWOULDBLOCK錯誤,而且緩衝區空間變得可用 
也就是說,收到首條FD_WRITE訊息,便應認為自己必然能在一個通訊端上發資料. 

3 WSAEventSelect 
你可以想象著,一排的空通訊端等著對方的串連... 
如上章所述,async投遞一個視窗常式,而Event投遞一個事件物件控點. 
或者更清楚解釋為,通訊端和事件對象對應著,當一個通訊端有事件發生,事件對象返回相應的值,通過這個值來索引這個通訊端。 
要注意該模式裡兩種工作狀態和模式,signaled/nonsignaled manual reset/auto reset 
一開始預設為未傳信(nonsignaled)和人工重設(manual reset)狀態,隨著網路事件的觸發,工作狀態從未船信到已傳信.在完成一個I/O請求處理後,要負責將工作狀態改變 

首先建立一個事件對象 WSAEVENT WSACreateEvent(void); 
其次將事件對象和通訊端聯絡在一起 int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, long lNetworkEvents); 
等待網路事件觸發事件物件控點狀態 DWORD WSAWaitForMultipleEvents(....DWORD dwTimeout, BOOL fAlertable); 
dwTimeout參數規定等待一個網路事件發生有多長時間,毫秒為單位.超過立即返回,即使由fWaitAll參數規定條件未滿足也如此.如果設為0, 函數會檢測指定的事件對象狀態,然後返回.這樣造成一個"輪詢",盡量避免設為0.若設為WSA_INFINITE,那麼只有在一個網路事件傳回一個事件對象後,才會返回. 
fAlertable:忽略,設為FALSE,主要用於重疊式I/O模型中 

將已傳信狀態更改為未傳信 BOOL WSAResetEvent(WSAEVENT hEvent); 
釋放事件控制代碼使用的系統資源 BOOL WSACloseEvent(WSAEVENT hEvent); 

現在還需解決的一問題是,怎麼獲得發生事件的通訊端,async直接用一個socket變數接收,而在event裡,是通過事先的一個數組索引獲得.這個方法名為WSAEnumNetworkEvents(); 

代碼架構如下: 
//先建立事件數目組和通訊端數組 
SOCKET Socket[常量]; 
WSAEVENT Event[]; 
DWORD EvenTotal = 0; 
//這裡進行通訊端準備到bind那步,建立一個事件,並且聯絡 
NewEvent = WSACreateEvent(); 
WSAEventSelect(Listen, NewEvent, FD_ACCEPT|FD_CLOSE); 

//最重要一步,加入到數組 
Socket[EventTotal] = Listen; 
Event[EventTotal] = NewEvent; 
EventTotal++; 

while(TRUE) 

//等待一個通訊端串連 
Index = WSAWaitForMultipleEvents(..); 
//在EnumNetworkEvents中進行查詢,判斷在哪個通訊端上,發生什麼網路事件類型. 
WSAEnumNetworkEvents( 
SocketArray[Index - WSA_WAIT_EVENT_0], 
EventArray[Index - WSA_WAIT_EVENT_0], 
NetworkEvents); 

對一個發生事件通訊端操作 
WSAWaitForMultipleEvents傳回值:減去預定值WSA_WAIT_EVENT_0 
Iindex = WSAWaitForMultipleEvents(..); 
MyEvent = EventArray[Index - WSA_WAIT_EVENT_0]; 
接下來可調用WSAEnumNetworkEvents函數,調查發生什麼類型網路事件 

4IO重疊 
對一個通訊端多次利用,利用CRITICAL_SECTION來進行互斥 

5。。。略

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.