SOCKET編程進階之Overlapped I\O事件通知模型

轉載

SOCKET編程進階之Overlapped I\O事件通知模型

WINSOCK I\O模型有六種: 
一:select模型 
二:WSAAsyncSelect模型 
三:WSAEventSelect模型 
四:Overlapped I/O 事件通知模型 
五:Overlapped I/O 完成例程模型 
六:完成端口IOCP模型 
且一個比一個完善,一個比一個高深。最好用的莫過於完成端口,但惋惜的是隻有NT、2000的系統才支持這種功能。心痛之餘,咱們只能寄但願於Overlapped I/O模型。 
下面,咱們來詳細分析一下重疊模型: 編程


1、重疊模型的優勢 
1)能夠運行在支持Winsock2的全部Windows平臺 ,而不像完成端口只是支持NT系統。 
2)比起阻塞、select、WSAAsyncSelect以及WSAEventSelect等模型,重疊I/O(Overlapped I/O)模型使應用程序能達到更佳的系統性能。 
由於它和這4種模型不一樣的是,使用重疊模型的應用程序通知緩衝區收發系統直接使用數據,也就是說,若是應用程序投遞了一個10KB大小的緩衝區來接收數據,且數據已經到達套接字,則該數據將直接被拷貝到投遞的緩衝區。 
而這4種模型種,數據到達並拷貝到單套接字接收緩衝區中,此時應用程序會被告知能夠讀入的容量。當應用程序調用接收函數以後,數據才從單套接字緩衝區拷貝到應用程序的緩衝區,差異就體現出來了。 
3)從《windows網絡編程》中提供的試驗結果中能夠看到,在使用了P4 1.7G Xero處理器(CPU很強啊)以及768MB的迴應服務器中,最大能夠處理4萬多個SOCKET鏈接,在處理1萬2千個鏈接的時候CPU佔用率才40% 左右 ―― 很是好的性能,已經直逼完成端口了^_^ windows


2、重疊模型的基本原理 
說了這麼多的好處,你必定也躍躍欲試了吧,不過咱們仍是要先提一下重疊模型的基本原理。 
歸納一點說,重疊模型是讓應用程序使用重疊數據結構(WSAOVERLAPPED),一次投遞一個或多個Winsock I/O請求。針對這些提交的請求,在它們完成以後,應用程序會收到通知,因而就能夠經過本身另外的代碼來處理這些數據了。 
須要注意的是,有兩個方法能夠用來管理重疊IO請求的完成狀況(就是說接到重疊操做完成的通知): 
1)事件對象通知(event object notification) 
2)完成例程(completion routines) ,注意,這裏並非完成端口 
而本文只是講述如何來使用事件通知的的方法實現重疊IO模型,完成例程的方法準備放到下一篇講 :) (內容太多了,一篇寫不完啊) ,如沒有特殊說明,本文的重疊模型默認就是指的基於事件通知的重疊模型。 
既然是基於事件通知,就要求將Windows事件對象與WSAOVERLAPPED結構關聯在一塊兒(WSAOVERLAPPED結構中專門有對應的參數),通俗一點講,就是。。。。對了,忘了說了,既然要使用重疊結構,咱們經常使用的send, sendto, recv, recvfrom也都要被WSASend, WSASendto, WSARecv, WSARecvFrom替換掉了, 它們的用法我後面會講到,這裏只須要注意一點,它們的參數中都有一個Overlapped參數,咱們能夠假設是把咱們的WSARecv這樣的操做操做「綁定」到這個重疊結構上,提交一個請求,其餘的事情就交給重疊結構去操心,而其中重疊結構又要與Windows的事件對象「綁定」在一塊兒,這樣咱們調用完WSARecv之後就能夠「不勞而獲」,等到重疊操做完成之後,天然會有與之對應的事件來通知咱們操做完成,而後咱們就能夠來根據重疊操做的結果取得咱們想要德數據了。 數組


3、關於重疊模型的基礎知識 
下面來介紹並舉例說明一下編寫重疊模型的程序中將會使用到的幾個關鍵函數。 
1)WSAOVERLAPPED結構 
這個結構天然是重疊模型裏的核心,它是這麼定義的 服務器

 

咱們須要把WSARecv等操做投遞到一個重疊結構上,而咱們又須要一個與重疊結構「綁定」在一塊兒的事件對象來通知咱們操做的完成,看到了和hEvent參數,不用我說大家也該知道如何來來把事件對象綁定到重疊結構上吧?大體以下: 
 網絡


2)WSARecv系列函數 
在重疊模型中,接收數據就要靠它了,它的參數也比recv要多,由於要用刀重疊結構嘛,它是這樣定義的: 
 

返回值: 
WSA_IO_PENDING : 最多見的返回值,這是說明咱們的WSARecv操做成功了,可是I/O操做尚未完成,因此咱們就須要綁定一個事件來通知咱們操做什麼時候完成 
其餘的函數我這裏就不一一介紹了,由於咱們畢竟還有MSDN,並且在講後面的完成例程和完成端口的時候我還會講到一些 ^_^ 

3)WSAWaitForMultipleEvents函數 
熟悉WSAEventSelect模型的朋友對這個函數確定不會陌生,不對,其實你們都不該該陌生,這個函數與線程中經常使用的WaitForMultipleObjects函數有些地方仍是比較像的,由於都是在等待某個事件的觸發嘛。 
由於咱們須要事件來通知咱們重疊操做的完成,因此天然須要這個等待事件的函數與之配套。 
 

返回值: 
WSA_WAIT_TIMEOUT :最多見的返回值,咱們須要作的就是繼續Wait 
WSA_WAIT_FAILED : 出現了錯誤,請檢查cEvents和lphEvents兩個參數是否有效 
若是事件數組中有某一個事件被傳信了,函數會返回這個事件的索引值,可是這個索引值須要減去預約義值 WSA_WAIT_EVENT_0纔是這個事件在事件數組中的位置。 
具體的例子就先不在這裏舉了,後面還會講到 
注意:WSAWaitForMultipleEvents函數只能支持由WSA_MAXIMUM_WAIT_EVENTS對象定義的一個最大值,是 64,就是說WSAWaitForMultipleEvents只能等待64個事件,若是想同時等待多於64個事件,就要 建立額外的工做者線程,就不得不去管理一個線程池,這一點就不以下一篇要講到的完成例程模型了。 

4)WSAGetOverlappedResult函數 
既然咱們能夠經過WSAWaitForMultipleEvents函數來獲得重疊操做完成的通知,那麼咱們天然也須要一個函數來查詢一下重疊操做的結果,定義以下 
 
1 BOOL WSAGetOverlappedResult(
2                           SOCKET s,                   // SOCKET,不用說了
3                           LPWSAOVERLAPPED lpOverlapped,  // 這裏是咱們想要查詢結果的那個重疊結構的指針
4                           LPDWORD lpcbTransfer,     // 本次重疊操做的實際接收(或發送)的字節數
5                           BOOL fWait,                // 設置爲TRUE,除非重疊操做完成,不然函數不會返回,設置FALSE,並且操做仍處於掛起狀態,那麼函數就會返回FALSE,錯誤爲WSA_IO_INCOMPLETE, 不過由於咱們是等待事件傳信來通知咱們操做完成,因此咱們這裏設,置成什麼都沒有做用…..-_-b  別仍雞蛋啊,我也想說得清楚一些…
6                           LPDWORD lpdwFlags       // 指向DWORD的指針,負責接收結果標誌
7                         );

這個函數沒什麼難的,這裏咱們也不須要去關注它的返回值,直接把參數填好調用就能夠了,這裏就先不舉例了 
惟一須要注意一下的就是若是WSAGetOverlappedResult完成之後,第三個參數返回是 0 ,則說明通訊對方已經關閉鏈接,咱們這邊的SOCKET, Event之類的也就能夠關閉了。數據結構

實現重疊模型的步驟做了這麼多的準備工做,費了這麼多的筆墨,咱們終於能夠開始着手編碼了。其實慢慢的你就會明白,要想透析重疊結構的內部原理也許是要費點功夫,可是隻是學會如何來使用它,倒是真的不難,惟一須要理清思路的地方就是和大量的客戶端交互的狀況下,咱們獲得事件通知之後,如何得知是哪個重疊操做完成了,繼而知道究竟該對哪個套接字進行處理,應該去哪一個緩衝區中的取得數據,everything will be OK^_^。下面咱們配合代碼,來一步步的講解如何親手完成一個重疊模型。 
下面是我寫的一個例子,用的標準C\C++,能夠直接編譯。 
因爲WSAWaitForMultipleEvents最多隻能同時等待64個消息,因此兩個線程最多支持64個鏈接,若要更多能夠在開一個線程,達到128個鏈接。以此類推,成線性增加。 
但線程過多的話,因爲CPU忙於在線程上下文之間的切換,也會影響程序的性能,因此這種模式,仍是不太適合很是多的鏈接數,如10000多個鏈接就不行了,這時,咱們只能用後面的完成例程或完成端口了,這也正是它的弊端所在。 app

相關文章
相關標籤/搜索