




版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
1、Windows下重疊I/O模型(轉貼)重疊模型的優(yōu)點可以運行在支持Winsock2的所有Windows平臺,而不像完成端口只是支持NT 系統(tǒng)。比起阻塞、select、WSAAsyncSelect 以及 WSAEventSelect 等模型,重疊 I/O(Overlapped I/O)模型使應用程序能達到更佳的系統(tǒng)性能。因為它和這4種模型不同的是,使用重疊模型的應用程序通 知緩沖區(qū)收發(fā)系統(tǒng)直接使用數(shù)據(jù),也就是說,如果應用程序投遞了一個10KB大 小的緩沖區(qū)來接收數(shù)據(jù),且數(shù)據(jù)已經(jīng)到達套接字,則該數(shù)據(jù)將直接被拷貝到投遞 的緩沖區(qū)。而這4種模型種,數(shù)據(jù)到達并拷貝到單套接字接收緩沖區(qū)中,此時應用程序 會
2、被告知可以讀入的容量。當應用程序調(diào)用接收函數(shù)之后,數(shù)據(jù)才從單套接字緩 沖區(qū)拷貝到應用程序的緩沖區(qū),差別就體現(xiàn)出來了。從windows網(wǎng)絡編程中提供的試驗結果中可以看到,在使用了 P4 1.7G Xero 處理器(CPU很強?。┮约?68MB的回應服務器中,最大可以處理4萬多個SOCKET 連接,在處理1萬2千個連接的時候CPU占用率才40%左右一一非常好的性 能,已經(jīng)直逼完成端口。重疊模型的基本原理說了這么多的好處,你一定也躍躍欲試了吧,不過我們還是要先提 一下重疊模型的基本原理。概括一點說,重疊模型是讓應用程序使用重疊數(shù)據(jù)結構 (WSAOVERLAPPED),一次投遞一個或多個Winsock
3、 I/O請求。針對這些提交的請 求,在它們完成之后,應用程序會收到通知,于是就可以通過自己另外的代碼來 處理這些數(shù)據(jù)了。需要注意的是,有兩個方法可以用來管理重疊IO請求的完成情況 (就是說接到重疊操作完成的通知):事件對象通知(event object notification)完成例程(completion routines),注意,這里并不是完成端口而本文只是講述如何來使用事件通知的的方法實現(xiàn)重疊IO模型,完成例程 的方法準備放到下一篇講:)(內(nèi)容太多了,一篇寫不完?。?,如沒有特殊說明,本文的重疊模型默認就是指的基于事件通知的重疊模型。既然是基于事件通知,就要求將Windows事件對象與W
4、SAOVERLAPPED結構關 聯(lián)在一起(WSAOVERLAPPED結構中專門有對應的參數(shù)),通俗一點講,就是。 對了,忘了說了,既然要使用重疊結構,我們常用的send, sendto, recv, recvfrom 也都要被 WSASend, WSASendto, WSARecv, WSARecvFrom 替換掉了,它 們的用法我后面會講到,這里只需要注意一點,它們的參數(shù)中都有一個 Overlapped參數(shù),我們可以假設是把我們的WSARecv這樣的操作操作“綁定” 到這個重疊結構上,提交一個請求,其他的事情就交給重疊結構去操心,而其中 重疊結構又要與Windows的事件對象“綁定”在一起,
5、這樣我們調(diào)用完WSARecv 以后就可以“坐享其成”,等到重疊操作完成以后,自然會有與之對應的事件來 通知我們操作完成,然后我們就可以來根據(jù)重疊操作的結果取得我們想要德數(shù)據(jù) 了。也許說了半天你還是不大明白,那就繼續(xù)往后面看吧。 -_-b,語言表達能力有限啊關于重疊模型的基礎知識下面來介紹并舉例說明一下編寫重疊模型的程序中將會使用到的幾 個關鍵函數(shù)。1. WSAOVERLAPPED 結構這個結構自然是重疊模型里的核心,它是這么定義的typedef struct _WSAOVERLAPPED (DWORD Internal;DWORD InternalHigh;DWORD Offset;DWORD
6、 OffsetHigh;WSAEVENT hEvent;/唯一需要關注的參數(shù),用來關聯(lián)WSAEvent 對象 WSAOVERLAPPED, *LPWSAOVERLAPPED;我們需要把WSARecv等操作投遞到一個重疊結構上,而我們又需要一個與重疊結 構“綁定”在一起的事件對象來通知我們操作的完成,看到了和hEvent參數(shù), 不用我說你們也該知道如何來來把事件對象綁定到重疊結構上吧?大致如下: WSAEVENT event;/ 定義事件WSAOVERLAPPED AcceptOverlapped ; / 定義重疊結構event = WSACreateEvent();/建立一個事件對象句柄Zer
7、oMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED); / 初始化重疊結 構AcceptOverlapped.hEvent = event; / Done !2. WSARecv系列函數(shù)在重疊模型中,接收數(shù)據(jù)就要靠它了,它的參數(shù)也比recv要多,因為要用刀重 疊結構嘛,它是這樣定義的:int WSARecv(SOCKET s,/當然是投遞這個操作的套接字一LPWSABUF lpBuffers,/ 接收緩沖區(qū),與Recv函數(shù)不同/需要一個由WSABUF結構構成的數(shù)組DWORD dwBufferCount,/ 數(shù)組中 WSABUF結構的數(shù)量LPDWORD
8、 lpNumberOfBytesRecvd, / 如果接收操作立即完成,這里會返回函數(shù)調(diào)用接收到的字節(jié)數(shù)LPDWORD lpFlags,/ 說來話長了,我們這里設置為0即可LPWSAOVERLAPPED lpOverlapped, / “綁定”的重疊結 構LPWSAOVERLAPPED_COMPLETION_ROUTINElpCompletionRoutine/完成例程中將會用到的參數(shù),我們這里設置為NULL);返回值:WSA_IO_PENDING :最常見的返回值,這是說明我們的WSARecv操作成功了,但是I/O操作還沒有完成,所以我們就需要綁定一個事件來通知我們操作何時完成舉個例子:(變
9、量的定義順序和上面的說明的順序是對應的,下同)SOCKET s;WSABUF DataBuf;/定義WSABUF結構的緩沖區(qū)/初始化一下DataBuf#define DATA_BUFSIZE 5096char bufferDATA_BUFSIZE;ZeroMemory(buffer, DATA_BUFSIZE);DataBuf.len = DATA_BUFSIZE;DataBuf.buf = buffer;DWORD dwBufferCount = 1, dwRecvBytes = 0, Flags = 0;/建立需要的重疊結構WSAOVERLAPPED AcceptOverlapped ;/
10、如果要處理多個操作,這里當然需要一 個/ WSAOVERLAPPED 數(shù)組WSAEVENT event;/如果要多個事件,這里當然也需要一個WSAEVENT數(shù)組/需要注意的是可能一個SOCKET同時會有一個以上的重疊請求,/也就會對應一個以上的WSAEVENTEvent = WSACreateEvent();ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED);AcceptOverlapped.hEvent = event;/ 關鍵的一步,把事件句柄“綁定”到重疊結構上/作了這么多工作,終于可以使用WSARecv來把我們的請求投遞到重疊結構上
11、了,呼。WSARecv(s, &DataBuf, dwBufferCount, &dwRecvBytes,&Flags, &AcceptOverlapped, NULL);其他的函數(shù)我這里就不一一介紹了,因為我們畢竟還有MSDN這么個好幫手,而 且在講后面的完成例程和完成端口的時候我還會講到一些”_”WSAWaitForMultipleEvents 函數(shù)熟悉WSAEventSelect模型的朋友對這個函數(shù)肯定不會陌生,不對,其實大家都 不應該陌生,這個函數(shù)與線程中常用的WaitForMultipleObjects函數(shù)有些地方 還是比較像的,因為都是在等待某個事件的觸發(fā)嘛。因為我們需要事件來通知
12、我們重疊操作的完成,所以自然需要這個等待事件的函 數(shù)與之配套。DWORD WSAWaitForMultipleEvents(DWORD cEvents,/等候事件的總數(shù)量const WSAEVENT* lphEvents,/事件數(shù)組的指針BOOL fWaitAll,/ 設置為TRUE,則事件數(shù)組中所有事件被傳信的時候函數(shù)才會返回/ FALSE則任何一個事件被傳信函數(shù)都要返回 /我們這里肯定是要設置為FALSE的DWORD dwTimeout, /超時時間,如果超時,函數(shù)會返回WSA_WAIT_TIMEOUT/如果設置為0,函數(shù)會立即返回/如果設置為WSA_INFINITE只有在某一個事件被傳信
13、后才會返回/在這里不建議設置為WSA_INFINITE,因為。后面再講吧.-_-bBOOL fAlertable/ 在完成例程中會用到這個參數(shù),這里我們先設置為FALSE);返回值:WSA_WAIT_TIMEOUT :最常見的返回值,我們需要做的就是繼續(xù)WaitWSA_WAIT_FAILED :出現(xiàn)了錯誤,請檢查 cEvents 和 lphEvents 兩個參 數(shù)是否有效如果事件數(shù)組中有某一個事件被傳信了,函數(shù)會返回這個事件的索引值,但是這 個索引值需要減去預定義值WSA_WAIT_EVENT_0才是這個事件在事件數(shù)組中的 位置。具體的例子就先不在這里舉了,后面還會講到注意:WSAWaitFo
14、rMultipleEvents 函數(shù)只能支持由 WSA_MAXIMUM_WAIT_EVENTS 對象定義的一個最大值,是64,就是說WSAWaitForMultipleEvents只能等待 64個事件,如果想同時等待多于64個事件,就要創(chuàng)建額外的工作者線程,就 不得不去管理一個線程池,這一點就不如下一篇要講到的完成例程模型了。WSAGetOverlappedResult 函數(shù)既然我們可以通過WSAWaitForMultipleEvents函數(shù)來得到重疊操作完成的通知,那么我們自然也需要一個函數(shù)來查詢一下重疊操作的結果,定義如下BOOL WSAGetOverlappedResult(SOCKET
15、 s,/ SOCKET,不用說了LPWSAOVERLAPPED lpOverlapped, / 這里是我們想要查詢結果的那個重疊結構的指針LPDWORD lpcbTransfer,/ 本次重疊操作的實際接收(或發(fā)送)的字節(jié)數(shù)BOOL fWait,/設置為TRUE,除非重疊操作完成,否則函數(shù)不會返回/設置FALSE,而且操作仍處于掛起狀態(tài),那么函數(shù)就會返回FALSE / 錯誤為 WSA_IO_INCOMPLETE /不過因為我們是等待事件傳信來通知我們操作完成,所以我們這里設置成什么 都沒有作用LPDWORD IpdwFlags/ 指向DWORD的指針,負責接收結果標志);這個函數(shù)沒什么難的,這
16、里我們也不需要去關注它的返回值,直接把參數(shù)填好調(diào) 用就可以了,這里就先不舉例了唯一需要注意一下的就是如果WSAGetOverlappedResult完成以后,第三個參數(shù) 返回是0,則說明通信對方已經(jīng)關閉連接,我們這邊的SOCKET, Event之類的 也就可以關閉了四。實現(xiàn)重疊模型的步驟作了這么多的準備工作,費了這么多的筆墨,我們終于可以開始著手編碼了。 其實慢慢的你就會明白,要想透析重疊結構的內(nèi)部原理也許是要費點功夫,但是 只是學會如何來使用它,卻是真的不難,唯一需要理清思路的地方就是和大量的 客戶端交互的情況下,我們得到事件通知以后,如何得知是哪一個重疊操作完成 了,繼而知道究竟該對哪一個
17、套接字進行處理,應該去哪個緩沖區(qū)中的取得數(shù)據(jù), everything will be OK。下面我們配合代碼,來一步步的講解如何親手完成一個重疊模型?!镜谝徊健慷x變量#define DATA_BUFSIZE4096/ 接收緩沖區(qū)大小SOCKETListenSocket,/ 監(jiān)聽套接字AcceptSocket;/與客戶端通信的套接字WSAOVERLAPPED AcceptOverlapped;/ 重疊結構一個WSAEVENT EventArrayWSA_MAXIMUM_WAIT_EVENTS;/用來通知重疊操作完成的事件句柄數(shù)組WSABUFDataBufDATA_BUFSIZE;DWORDdw
18、EventTotal = 0,/ 程序中事件的總數(shù)dwRecvBytes = 0,/ 接收到的字符長度Flags = 0;/ WSARecv的參數(shù)【第二步】創(chuàng)建一個套接字,開始在指定的端口上監(jiān)聽連接請求 和其他的SOCKET初始化全無二致,直接照搬即可,在此也不多費唇舌了,需要 注意的是為了一目了然,我去掉了錯誤處理,平常可不要這樣啊,盡管這里出錯 的幾率比較小。WSADATA wsaData;WSAStartup(MAKEWORD(2,2),&wsaData);ListenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 創(chuàng)建 TCP套接字S
19、OCKADDR_IN ServerAddr;分配端口及協(xié)議族并綁定ServerAddr.sin_family=AF_INET;ServerAddr.sin_addr.S_un.S_addr =htonl(INADDR_ANY);ServerAddr.sin_port=htons(11111);bind(ListenSocket,(LPSOCKADDR)&ServerAddr, sizeof(ServerAddr); / 綁 定套接字listen(ListenSocket, 5);開始監(jiān)聽【第三步】接受一個入站的連接請求AcceptSocket = accept (ListenSocket, N
20、ULL,NULL);當然,這里是我偷懶,如果想要獲得連入客戶端的信息(記得論壇上也常有人問 到),accept的后兩個參數(shù)就不要用NULL,而是這樣SOCKADDR_IN ClientAddr;/ 定義一個客戶端得地址結構作為參數(shù) int addr_length二sizeof(ClientAddr);AcceptSocket = accept(ListenSocket,(SOCKADDR*)&ClientAddr, &addr_length);/于是乎,我們就可以輕松得知連入客戶端的信息了LPCTSTR lpIP = inet_ntoa(ClientAddr.sin_addr);/ IPUIN
21、T nPort = ClientAddr.sin_port;/ Port【第四步】建立并初始化重疊結構為連入的這個套接字新建立一個WSAOVERLAPPED重疊結構,并且象前面講到的那 樣,為這個重疊結構從事件句柄數(shù)組里挑出一個空閑的對象句柄“綁定”上去。/創(chuàng)建一個事件/ dwEventTotal可以暫時先作為Event數(shù)組的索引EventArraydwEventTotal = WSACreateEvent();ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED);/ 置今AcceptOverlapped.hEvent = EventArray
22、dwEventTotal;/關聯(lián)事件char bufferDATA_BUFSIZE;ZeroMemory(buffer, DATA_BUFSIZE);DataBuf.len = DATA_BUFSIZE;DataBuf.buf = buffer;/初始化一個WSABUF結構dwEventTotal +;總數(shù)加一【第五步】以WSAOVERLAPPED結構為參數(shù),在套接字上投遞WSARecv請求各個變量都已經(jīng)初始化OK以后,我們就可以開始Socket操作了,然后讓 WSAOVERLAPPED結構來替我們管理I/O請求,我們只用等待事件的觸發(fā)就OK 了。if(WSARecv(AcceptSocket
23、 ,&DataBuf,1,&dwRecvBytes,&Flags,& AcceptOverlapped, NULL) = SOCKET_ERROR)(/返回WSA_IO_PENDING是正常情況,表示IO操作正在進行,不能立即完 成/如果不是WSA_IO_PENDING錯誤,就大事不好了! !if(WSAGetLastError() != WSA_IO_PENDING) (/那就只能關閉大吉了closesocket(AcceptSocket);WSACloseEvent(EventArraydwEventTotal); 【第六步】 用WSAWaitForMultipleEvents函數(shù)等待重疊
24、操作返回的結果我們前面已經(jīng)給WSARecv關聯(lián)的重疊結構賦了一個事件對象句柄,所以我們 這里要等待事件對象的觸發(fā)與之配合,而且需要根據(jù)WSAWaitForMultipleEvents函數(shù)的返回值來確定究竟事件數(shù)組中的哪一個事件 被觸發(fā)了,這個函數(shù)的用法及返回值請參考前面的基礎知識部分。DWORD dwIndex;/等候重疊I/O調(diào)用結束/因為我們把事件和Overlapped綁定在一起,重疊操作完成后我們會接到事件 通知dwIndex = WSAWaitForMultipleEvents(dwEventTotal,EventArray ,FALSE ,WSA_INFINITE,FALSE);/注
25、意這里返回的Index并非是事件在數(shù)組里的Index,而是需要減去WSA_WAIT_EVENT_0dwIndex = dwIndex - WSA_WAIT_EVENT_0;【第七步】使用WSAResetEvent函數(shù)重設當前這個用完的事件對象事件已經(jīng)被觸發(fā)了之后,它對于我們來說已經(jīng)沒有利用價值了,所以要將它重置 一下留待下一次使用,很簡單,就一步,連返回值都不用考慮WSAResetEvent(EventArraydwIndex);【第八步】使用WSAGetOverlappedResult函數(shù)取得重疊調(diào)用的返回狀態(tài)這是我們最關心的事情,費了那么大勁投遞的這個重疊操作究竟是個什么結 果呢?其實對于
26、本模型來說,唯一需要檢查一下的就是對方的Socket連接是否 已經(jīng)關閉了DWORD dwBytesTransferred;WSAGetOverlappedResult( AcceptSocket, AcceptOverlapped , &dwBytesTransferred, FALSE, &Flags);/先檢查通信對方是否已經(jīng)關閉連接/如果=0則表示連接已經(jīng),則關閉套接字if(dwBytesTransferred = 0)(closesocket(AcceptSocket);WSACloseEvent(EventArraydwIndex); / 關閉事件 return;【第九步】“享受”接
27、收到的數(shù)據(jù)如果程序執(zhí)行到了這里,那么就說明一切正常,WSABUF結構里面就存有我們 WSARecv來的數(shù)據(jù)了,終于到了盡情享用成果的時候了!喝杯茶,休息一下吧DataBuf.buf就是一個char*字符串指針,聽憑你的處理吧,我就不多說了【第十步】同第五步一樣,在套接字上繼續(xù)投遞WSARecv請求,重復步驟69這樣一路作下來,我們終于可以從客戶端接收到數(shù)據(jù)了,但是回想起來,呀,這樣豈不是只能收到一次數(shù)據(jù),然后程序不就Over 了?.-_-b 所 以我們接下來不得不重復一遍第四步和第五步的工作,再次在這個套接字上投遞 另一個WSARecv請求,并且使整個過程循環(huán)起來,are u clear?大家
28、可以參考我的代碼,在這里就先不寫了,因為各位都一定比我 smart,領悟了關鍵所在以后,稍作思考就可以靈活變通了。客戶端情況的注意事項完成了上面的循環(huán)以后,重疊模型就已經(jīng)基本上搭建好了 80%了,為 什么不是100%呢?因為仔細一回想起來,呀,這樣豈不是只能連接一個客戶端?是的,如果只處理一個客戶端,那重疊模型就半點優(yōu)勢也沒有了,我 們正是要使用重疊模型來處理多個客戶端。所以我們不得不再對結構作一些改動。首先,肯定是需要一個SOCKET數(shù)組,分別用來和每一個SOCKET通信其次,因為重疊模型中每一個SOCKET操作都是要“綁定”一個重疊結構的,所 以需要為每一個SOCKET操作搭配一個WSAO
29、VERLAPPED結構,但是這樣說并不嚴 格,因為如果每一個SOCKET同時只有一個操作,比如WSARecv,那么一個SOCKET 就可以對應一個WSAOVERLAPPED結構,但是如果一個SOCKET上會有WSARecv和 WSASend兩個操作,那么一個SOCKET肯定就要對應兩個WSAOVERLAPPED結構, 所以有多少個SOCKET操作就會有多少個WSAOVERLAPPED結構。然后,同樣是為每一個WSAOVERLAPPED結構都要搭配一個WSAEVENT事件,所以 說有多少個SOCKET操作就應該有多少個WSAOVERLAPPED結構,有多少個 WSAOVERLAPPED結構就應該有多少個WSAEVENT事件,最好把SOCKET - WSAOVERLAPPED - WSAEVENT三者的關聯(lián)起來,到了關鍵時刻才會臨危不亂:)不得不分作兩個線程:一個用來循環(huán)監(jiān)聽端口,接收請求的連接,然后給在這個套接字上配合一個 WSAOVERLAPPED結構投遞第一個WSARecv請求,然后進入第二個線程中等待操作 完成。第二個線程用來不
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 修路建設施工合同范本
- 勞務銷售聘用合同范本
- 產(chǎn)品購買合同范本英文
- 光盤出版合同范本
- 上海保姆合同范本
- 項目成本預算管理制度
- 雙飛粉 涂料合同范本
- 印尼倉庫租賃合同范本
- 個體分紅股合同范本
- 糧油蔬菜配送合同范本
- 旅游景區(qū)旅游安全風險評估報告
- 門窗安裝工程投標書范本(二)
- 追覓科技在線測評題
- 智鼎在線測評107題
- 病歷書寫規(guī)范與住院病歷質(zhì)量監(jiān)控管理制度
- 12詩詞四首《漁家傲-秋思》公開課一等獎創(chuàng)新教學設計 初中語文九年級下冊
- 金礦承包協(xié)議合同2024年
- 解讀國有企業(yè)管理人員處分條例(2024)課件(全文)
- 創(chuàng)新創(chuàng)業(yè)基礎-理論、案例與訓練(大學生創(chuàng)新創(chuàng)業(yè)教育課程)全套教學課件
- TD/T 1072-2022 國土調(diào)查坡度分級圖制作技術規(guī)定(正式版)
- DZ∕T 0148-2014 水文水井地質(zhì)鉆探規(guī)程(正式版)
評論
0/150
提交評論