手把手教你玩轉(zhuǎn)SOCKET模型之重疊IO篇_第1頁
手把手教你玩轉(zhuǎn)SOCKET模型之重疊IO篇_第2頁
手把手教你玩轉(zhuǎn)SOCKET模型之重疊IO篇_第3頁
手把手教你玩轉(zhuǎn)SOCKET模型之重疊IO篇_第4頁
手把手教你玩轉(zhuǎn)SOCKET模型之重疊IO篇_第5頁
已閱讀5頁,還剩3頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、手把手教你玩轉(zhuǎn)SOCKET模型之重疊I/O篇“身為一個(gè)初學(xué)者,時(shí)常能體味到初學(xué)者入門的艱辛,所以總是想抽空作點(diǎn)什么來盡我所能的幫助那些需要幫助的人。我也希望大家能把自己的所學(xué)和他人一起分享,不要去鄙視別人索取時(shí)的貪婪,因?yàn)樽顟?yīng)該被鄙視的是不肯付出時(shí)的吝嗇?!?- 題記 By PiggyXP(小豬)前 言 其實(shí)我首先應(yīng)該道歉,因?yàn)?月份的時(shí)候曾信誓旦旦的說要寫一套關(guān)于SOCKET所有模型的入門文章以及配套代碼,不過沒想到后天竟然被美女所迷出去度假了,剛剛回來不久。-_-b其實(shí)那些模型的配套代碼我已經(jīng)基本寫完了,只是沒寫配套文字,不過我想還是先從稍微難一點(diǎn)的模型寫起吧,因?yàn)槠渌P偷娜腴T畢竟要簡(jiǎn)單

2、一些。不過由于也是初學(xué)者,疏漏之處還望不吝指正。本文凝聚著筆者心血,如要轉(zhuǎn)載,請(qǐng)指明原作者及出處,謝謝!_OK, Lets go ! Have fun!! q_p本文配套的示例源碼下載地址(VC.net 2003編寫的多客戶端MFC代碼,配有詳盡注釋,只是簡(jiǎn)單的顯示一下客戶端發(fā)來的字符,稍加改進(jìn)就是個(gè)聊天室了):/PiggyXP/OverlappedModel.rar(unix系統(tǒng),千萬注意鏈接大小寫)非常感謝網(wǎng)絡(luò)版的limin兄弟為我無償提供的空間,以及在我學(xué)習(xí)過程中給我的大力幫助與支持,真的非常感謝他,感激涕零啊T_T也歡迎大家光臨他的Blog一起

3、討論網(wǎng)絡(luò)技術(shù)/(本文假設(shè)你已經(jīng)具備用SOCKET簡(jiǎn)單模型編程的能力,如果對(duì)SOCKET一無所知請(qǐng)關(guān)注本系列其他文章)目錄:1 重疊模型的優(yōu)點(diǎn)2 重疊模型的基本原理3 關(guān)于重疊模型的基礎(chǔ)知識(shí)4 重疊模型的實(shí)現(xiàn)步驟5 多客戶端情況的注意事項(xiàng)一 重疊模型的優(yōu)點(diǎn)1. 可以運(yùn)行在支持Winsock2的所有Windows平臺(tái) ,而不像完成端口只是支持NT系統(tǒng)。2. 比起阻塞、select、WSAAsyncSelect以及WSAEventSelect等模型,重疊I/O(Overlapped I/O)模型使應(yīng)用程序能達(dá)到更佳的系統(tǒng)性能。 因?yàn)樗瓦@4種模型不同的是,

4、使用重疊模型的應(yīng)用程序通知緩沖區(qū)收發(fā)系統(tǒng)直接使用數(shù)據(jù),也就是說,如果應(yīng)用程序投遞了一個(gè)10KB大小的緩沖區(qū)來接收數(shù)據(jù),且數(shù)據(jù)已經(jīng)到達(dá)套接字,則該數(shù)據(jù)將直接被拷貝到投遞的緩沖區(qū)。而這4種模型種,數(shù)據(jù)到達(dá)并拷貝到單套接字接收緩沖區(qū)中,此時(shí)應(yīng)用程序會(huì)被告知可以讀入的容量。當(dāng)應(yīng)用程序調(diào)用接收函數(shù)之后,數(shù)據(jù)才從單套接字緩沖區(qū)拷貝到應(yīng)用程序的緩沖區(qū),差別就體現(xiàn)出來了。3. 從windows網(wǎng)絡(luò)編程中提供的試驗(yàn)結(jié)果中可以看到,在使用了P4 1.7G Xero處理器(CPU很強(qiáng)啊)以及768MB的回應(yīng)服務(wù)器中,最大可以處理4萬多個(gè)SOCKET連接,在處理1萬2千個(gè)連接的時(shí)候CPU占用率才40% 左右 非常好的

5、性能,已經(jīng)直逼完成端口了_二 重疊模型的基本原理 說了這么多的好處,你一定也躍躍欲試了吧,不過我們還是要先提一下重疊模型的基本原理。 概括一點(diǎn)說,重疊模型是讓應(yīng)用程序使用重疊數(shù)據(jù)結(jié)構(gòu)(WSAOVERLAPPED),一次投遞一個(gè)或多個(gè)Winsock I/O請(qǐng)求。針對(duì)這些提交的請(qǐng)求,在它們完成之后,應(yīng)用程序會(huì)收到通知,于是就可以通過自己另外的代碼來處理這些數(shù)據(jù)了。 需要注意的是,有兩個(gè)方法可以用來管理重疊IO請(qǐng)求的完成情況(就是說接到重疊操作完成的通知):1. 事件對(duì)象通知(event object notification) 2. 完成例程(completion routines) ,注意,這里

6、并不是完成端口而本文只是講述如何來使用事件通知的的方法實(shí)現(xiàn)重疊IO模型,完成例程的方法準(zhǔn)備放到下一篇講 :) (內(nèi)容太多了,一篇寫不完啊) ,如沒有特殊說明,本文的重疊模型默認(rèn)就是指的基于事件通知的重疊模型。既然是基于事件通知,就要求將Windows事件對(duì)象與WSAOVERLAPPED結(jié)構(gòu)關(guān)聯(lián)在一起(WSAOVERLAPPED結(jié)構(gòu)中專門有對(duì)應(yīng)的參數(shù)),通俗一點(diǎn)講,就是。對(duì)了,忘了說了,既然要使用重疊結(jié)構(gòu),我們常用的send, sendto, recv, recvfrom也都要被WSASend, WSASendto, WSARecv, WSARecvFrom替換掉了, 它們的用法我后面會(huì)講到,這

7、里只需要注意一點(diǎn),它們的參數(shù)中都有一個(gè)Overlapped參數(shù),我們可以假設(shè)是把我們的WSARecv這樣的操作操作“綁定”到這個(gè)重疊結(jié)構(gòu)上,提交一個(gè)請(qǐng)求,其他的事情就交給重疊結(jié)構(gòu)去操心,而其中重疊結(jié)構(gòu)又要與Windows的事件對(duì)象“綁定”在一起,這樣我們調(diào)用完WSARecv以后就可以“坐享其成”,等到重疊操作完成以后,自然會(huì)有與之對(duì)應(yīng)的事件來通知我們操作完成,然后我們就可以來根據(jù)重疊操作的結(jié)果取得我們想要德數(shù)據(jù)了。 也許說了半天你還是不大明白,那就繼續(xù)往后面看吧。-_-b,語言表達(dá)能力有限啊三 關(guān)于重疊模型的基礎(chǔ)知識(shí)下面來介紹并舉例說明一下編寫重疊模型的程序中將會(huì)使用到的幾個(gè)關(guān)鍵函數(shù)。1. W

8、SAOVERLAPPED結(jié)構(gòu)這個(gè)結(jié)構(gòu)自然是重疊模型里的核心,它是這么定義的typedef struct _WSAOVERLAPPED DWORD Internal; DWORD InternalHigh; DWORD Offset; DWORD OffsetHigh; WSAEVENT hEvent; / 唯一需要關(guān)注的參數(shù),用來關(guān)聯(lián)WSAEvent對(duì)象 WSAOVERLAPPED, *LPWSAOVERLAPPED;我們需要把WSARecv等操作投遞到一個(gè)重疊結(jié)構(gòu)上,而我們又需要一個(gè)與重疊結(jié)構(gòu)“綁定”在一起的事件對(duì)象來通知我們操作的完成,看到了和hEvent參數(shù),不用我說你們也該知道如何來來

9、把事件對(duì)象綁定到重疊結(jié)構(gòu)上吧?大致如下:WSAEVENT event; / 定義事件WSAEVENT event; / 定義事件WSAOVERLAPPED AcceptOverlapped ; / 定義重疊結(jié)構(gòu)event = WSACreateEvent(); / 建立一個(gè)事件對(duì)象句柄ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED); / 初始化重疊結(jié)構(gòu)AcceptOverlapped.hEvent = event; / Done !!2. WSARecv系列函數(shù)在重疊模型中,接收數(shù)據(jù)就要靠它了,它的參數(shù)也比recv要多,因?yàn)橐玫吨丿B結(jié)構(gòu)

10、嘛,它是這樣定義的: int WSARecv( SOCKET s, / 當(dāng)然是投遞這個(gè)操作的套接字 LPWSABUF lpBuffers, / 接收緩沖區(qū),與Recv函數(shù)不同/ 這里需要一個(gè)由WSABUF結(jié)構(gòu)構(gòu)成的數(shù)組 DWORD dwBufferCount, / 數(shù)組中WSABUF結(jié)構(gòu)的數(shù)量 LPDWORD lpNumberOfBytesRecvd, / 如果接收操作立即完成,這里會(huì)返回函數(shù)調(diào)用/ 所接收到的字節(jié)數(shù) LPDWORD lpFlags, / 標(biāo)志,說來話長(zhǎng)了,我們這里設(shè)置為0 即可 LPWSAOVERLAPPED lpOverlapped, / “綁定”的重疊結(jié)構(gòu) LPWSAOV

11、ERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine / 完成例程中將會(huì)用到的參數(shù),我們這里設(shè)置為 NULL);返回值:WSA_IO_PENDING : 最常見的返回值,這是說明我們的WSARecv操作成功了,但是I/O操作還沒有完成,所以我們就需要綁定一個(gè)事件來通知我們操作何時(shí)完成舉個(gè)例子:(變量的定義順序和上面的說明的順序是對(duì)應(yīng)的,下同)SOCKET s;WSABUF DataBuf; / 定義WSABUF結(jié)構(gòu)的緩沖區(qū)/ 初始化一下DataBuf#define DATA_BUFSIZE 5096char bufferDATA_BUFSIZE;Zer

12、oMemory(buffer, DATA_BUFSIZE);DataBuf.len = DATA_BUFSIZE;DataBuf.buf = buffer;DWORD dwBufferCount = 1, dwRecvBytes = 0, Flags = 0;/ 建立需要的重疊結(jié)構(gòu)WSAOVERLAPPED AcceptOverlapped ;/ 如果要處理多個(gè)操作,這里當(dāng)然需要一個(gè)/ WSAOVERLAPPED數(shù)組WSAEVENT event; / 如果要多個(gè)事件,這里當(dāng)然也需要一個(gè)WSAEVENT數(shù)組 / 需要注意的是可能一個(gè)SOCKET同時(shí)會(huì)有一個(gè)以上的重疊請(qǐng)求,/ 也就會(huì)對(duì)應(yīng)一個(gè)以上的

13、WSAEVENTEvent = WSACreateEvent();ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED);AcceptOverlapped.hEvent = event; / 關(guān)鍵的一步,把事件句柄“綁定”到重疊結(jié)構(gòu)上/ 做了這么多工作,終于可以使用WSARecv來把我們的請(qǐng)求投遞到重疊結(jié)構(gòu)上了,呼。WSARecv(s, &DataBuf, dwBufferCount, &dwRecvBytes, &Flags, &AcceptOverlapped, NULL);其他的函數(shù)我這里就不一一介紹了,因?yàn)槲覀儺吘惯€有MSDN這么個(gè)好幫手

14、,而且在講后面的完成例程和完成端口的時(shí)候我還會(huì)講到一些 _3. WSAWaitForMultipleEvents函數(shù)熟悉WSAEventSelect模型的朋友對(duì)這個(gè)函數(shù)肯定不會(huì)陌生,不對(duì),其實(shí)大家都不應(yīng)該陌生,這個(gè)函數(shù)與線程中常用的WaitForMultipleObjects函數(shù)有些地方還是比較像的,因?yàn)槎际窃诘却硞€(gè)事件的觸發(fā)嘛。因?yàn)槲覀冃枰录硗ㄖ覀冎丿B操作的完成,所以自然需要這個(gè)等待事件的函數(shù)與之配套。DWORD WSAWaitForMultipleEvents( DWORD cEvents, / 等候事件的總數(shù)量 const WSAEVENT* lphEvents, / 事件數(shù)組的

15、指針 BOOL fWaitAll, / 這個(gè)要多說兩句: / 如果設(shè)置為 TRUE,則事件數(shù)組中所有事件被傳信的時(shí)候函數(shù)才會(huì)返回 / FALSE則任何一個(gè)事件被傳信函數(shù)都要返回 / 我們這里肯定是要設(shè)置為FALSE的 DWORD dwTimeout, / 超時(shí)時(shí)間,如果超時(shí),函數(shù)會(huì)返回 WSA_WAIT_TIMEOUT/ 如果設(shè)置為0,函數(shù)會(huì)立即返回/ 如果設(shè)置為 WSA_INFINITE只有在某一個(gè)事件被傳信后才會(huì)返回/ 在這里不建議設(shè)置為WSA_INFINITE,因?yàn)?。后面再講吧.-_-b BOOL fAlertable / 在完成例程中會(huì)用到這個(gè)參數(shù),這里我們先設(shè)置為FALSE);返回值

16、:WSA_WAIT_TIMEOUT :最常見的返回值,我們需要做的就是繼續(xù)WaitWSA_WAIT_FAILED : 出現(xiàn)了錯(cuò)誤,請(qǐng)檢查cEvents和lphEvents兩個(gè)參數(shù)是否有效如果事件數(shù)組中有某一個(gè)事件被傳信了,函數(shù)會(huì)返回這個(gè)事件的索引值,但是這個(gè)索引值需要減去預(yù)定義值WSA_WAIT_EVENT_0才是這個(gè)事件在事件數(shù)組中的位置。具體的例子就先不在這里舉了,后面還會(huì)講到.注意:WSAWaitForMultipleEvents函數(shù)只能支持由WSA_MAXIMUM_WAIT_EVENTS對(duì)象定義的一個(gè)最大值,是 64,就是說WSAWaitForMultipleEvents只能等待64個(gè)

17、事件,如果想同時(shí)等待多于64個(gè)事件,就要 創(chuàng)建額外的工作者線程,就不得不去管理一個(gè)線程池,這一點(diǎn)就不如下一篇要講到的完成例程模型了。4. WSAGetOverlappedResult函數(shù)既然我們可以通過WSAWaitForMultipleEvents函數(shù)來得到重疊操作完成的通知,那么我們自然也需要一個(gè)函數(shù)來查詢一下重疊操作的結(jié)果,定義如下BOOL WSAGetOverlappedResult( SOCKET s, / SOCKET,不用說了 LPWSAOVERLAPPED lpOverlapped, / 這里是我們想要查詢結(jié)果的那個(gè)重疊結(jié)構(gòu)的指針 LPDWORD lpcbTransfer, /

18、 本次重疊操作的實(shí)際接收(或發(fā)送)的字節(jié)數(shù) BOOL fWait, / 設(shè)置為TRUE,除非重疊操作完成,否則函數(shù)不會(huì)返回 / 設(shè)置FALSE,而且操作仍處于掛起狀態(tài),那么函數(shù)就會(huì)返回FALSE / 錯(cuò)誤為WSA_IO_INCOMPLETE / 不過因?yàn)槲覀兪堑却录餍艁硗ㄖ覀儾僮魍瓿?,所以我們這里設(shè) / 置成什么都沒有作用.-_-b 別仍雞蛋啊,我也想說得清楚一些 LPDWORD lpdwFlags / 指向DWORD的指針,負(fù)責(zé)接收結(jié)果標(biāo)志);這個(gè)函數(shù)沒什么難的,這里我們也不需要去關(guān)注它的返回值,直接把參數(shù)填好調(diào)用就可以了,這里就先不舉例了唯一需要注意一下的就是如果WSAGetOver

19、lappedResult完成以后,第三個(gè)參數(shù)返回是 0 ,則說明通信對(duì)方已經(jīng)關(guān)閉連接,我們這邊的SOCKET, Event之類的也就可以關(guān)閉了。四。 實(shí)現(xiàn)重疊模型的步驟作了這么多的準(zhǔn)備工作,費(fèi)了這么多的筆墨,我們終于可以開始著手編碼了。其實(shí)慢慢的你就會(huì)明白,要想透析重疊結(jié)構(gòu)的內(nèi)部原理也許是要費(fèi)點(diǎn)功夫,但是只是學(xué)會(huì)如何來使用它,卻是真的不難,唯一需要理清思路的地方就是和大量的客戶端交互的情況下,我們得到事件通知以后,如何得知是哪一個(gè)重疊操作完成了,繼而知道究竟該對(duì)哪一個(gè)套接字進(jìn)行處理,應(yīng)該去哪個(gè)緩沖區(qū)中的取得數(shù)據(jù),everything will be OK_。下面我們配合代碼,來一步步的講解如何

20、親手完成一個(gè)重疊模型。第一步】定義變量#define DATA_BUFSIZE 4096 / 接收緩沖區(qū)大小SOCKET ListenSocket, / 監(jiān)聽套接字AcceptSocket; / 與客戶端通信的套接字WSAOVERLAPPED AcceptOverlapped; / 重疊結(jié)構(gòu)一個(gè)WSAEVENT EventArrayWSA_MAXIMUM_WAIT_EVENTS; / 用來通知重疊操作完成的事件句柄數(shù)組WSABUF DataBufDATA_BUFSIZE ; / 定義WSABUF結(jié)構(gòu)的緩沖區(qū)DWORD dwEventTotal = 0, / 程序中事件的總數(shù) dwRecvByt

21、es = 0, / 接收到的字符長(zhǎng)度 Flags = 0; / WSARecv的參數(shù)【第二步】創(chuàng)建一個(gè)套接字,開始在指定的端口上監(jiān)聽連接請(qǐng)求和其他的SOCKET初始化全無二致,直接照搬即可,在此也不多費(fèi)唇舌了,需要注意的是為了一目了然,我去掉了錯(cuò)誤處理,平??刹灰@樣啊,盡管這里出錯(cuò)的幾率比較小。WSADATA wsaData;WSAStartup(MAKEWORD(2,2),&wsaData);ListenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); /創(chuàng)建TCP套接字SOCKADDR_IN ServerAddr; /分配端口及協(xié)議族并綁

22、定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)聽【第三步】接受一個(gè)入站的連接請(qǐng)求 一個(gè)accept就完了,都是一樣一樣一樣一樣的啊 至于AcceptEx的使用,在完成端口中我會(huì)講到,這里就先不一次灌輸這么多了,不消

23、化啊_ AcceptSocket = accept (ListenSocket, NULL,NULL) ; 當(dāng)然,這里是我偷懶,如果想要獲得連入客戶端的信息(記得論壇上也常有人問到),accept的后兩個(gè)參數(shù)就不要用NULL,而是這樣SOCKADDR_IN ClientAddr; / 定義一個(gè)客戶端得地址結(jié)構(gòu)作為參數(shù)int addr_length=sizeof(ClientAddr);AcceptSocket = accept(ListenSocket,(SOCKADDR*)&ClientAddr, &addr_length);/ 于是乎,我們就可以輕松得知連入客戶端的信息了LPCTSTR l

24、pIP = inet_ntoa(ClientAddr.sin_addr); / IPUINT nPort = ClientAddr.sin_port; / Port【第四步】建立并初始化重疊結(jié)構(gòu)為連入的這個(gè)套接字新建立一個(gè)WSAOVERLAPPED重疊結(jié)構(gòu),并且象前面講到的那樣,為這個(gè)重疊結(jié)構(gòu)從事件句柄數(shù)組里挑出一個(gè)空閑的對(duì)象句柄“綁定”上去。/ 創(chuàng)建一個(gè)事件/ dwEventTotal可以暫時(shí)先作為Event數(shù)組的索引EventArraydwEventTotal = WSACreateEvent(); ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERL

25、APPED); / 置零AcceptOverlapped.hEvent = EventArraydwEventTotal; / 關(guān)聯(lián)事件char bufferDATA_BUFSIZE;ZeroMemory(buffer, DATA_BUFSIZE);DataBuf.len = DATA_BUFSIZE;DataBuf.buf = buffer; / 初始化一個(gè)WSABUF結(jié)構(gòu)dwEventTotal +; / 總數(shù)加一【第五步】以WSAOVERLAPPED結(jié)構(gòu)為參數(shù),在套接字上投遞WSARecv請(qǐng)求各個(gè)變量都已經(jīng)初始化OK以后,我們就可以開始Socket操作了,然后讓W(xué)SAOVERLAPPED

26、結(jié)構(gòu)來替我們管理I/O 請(qǐng)求,我們只用等待事件的觸發(fā)就OK了。if(WSARecv(AcceptSocket ,&DataBuf,1,&dwRecvBytes,&Flags,& AcceptOverlapped, NULL) = SOCKET_ERROR) / 返回WSA_IO_PENDING是正常情況,表示IO操作正在進(jìn)行,不能立即完成 / 如果不是WSA_IO_PENDING錯(cuò)誤,就大事不好了!if(WSAGetLastError() != WSA_IO_PENDING) / 那就只能關(guān)閉大吉了closesocket(AcceptSocket);WSACloseEvent(EventArr

27、aydwEventTotal);【第六步】用WSAWaitForMultipleEvents函數(shù)等待重疊操作返回的結(jié)果 我們前面已經(jīng)給WSARecv關(guān)聯(lián)的重疊結(jié)構(gòu)賦了一個(gè)事件對(duì)象句柄,所以我們這里要等待事件對(duì)象的觸發(fā)與之配合,而且需要根據(jù)WSAWaitForMultipleEvents函數(shù)的返回值來確定究竟事件數(shù)組中的哪一個(gè)事件被觸發(fā)了,這個(gè)函數(shù)的用法及返回值請(qǐng)參考前面的基礎(chǔ)知識(shí)部分。DWORD dwIndex;/ 等候重疊I/O調(diào)用結(jié)束/ 因?yàn)槲覀儼咽录蚈verlapped綁定在一起,重疊操作完成后我們會(huì)接到事件通知dwIndex = WSAWaitForMultipleEvents(dw

28、EventTotal, EventArray ,FALSE ,WSA_INFINITE,FALSE);/ 注意這里返回的Index并非是事件在數(shù)組里的Index,而是需要減去WSA_WAIT_EVENT_0dwIndex = dwIndex WSA_WAIT_EVENT_0;【第七步】使用WSAResetEvent函數(shù)重設(shè)當(dāng)前這個(gè)用完的事件對(duì)象事件已經(jīng)被觸發(fā)了之后,它對(duì)于我們來說已經(jīng)沒有利用價(jià)值了,所以要將它重置一下留待下一次使用,很簡(jiǎn)單,就一步,連返回值都不用考慮WSAResetEvent(EventArraydwIndex);【第八步】使用WSAGetOverlappedResult函數(shù)取

29、得重疊調(diào)用的返回狀態(tài) 這是我們最關(guān)心的事情,費(fèi)了那么大勁投遞的這個(gè)重疊操作究竟是個(gè)什么結(jié)果呢?其實(shí)對(duì)于本模型來說,唯一需要檢查一下的就是對(duì)方的Socket連接是否已經(jīng)關(guān)閉了DWORD dwBytesTransferred;WSAGetOverlappedResult( AcceptSocket, AcceptOverlapped ,&dwBytesTransferred, FALSE, &Flags);/ 先檢查通信對(duì)方是否已經(jīng)關(guān)閉連接/ 如果=0則表示連接已經(jīng),則關(guān)閉套接字if(dwBytesTransferred = 0)closesocket(AcceptSocket); WSAClos

30、eEvent(EventArraydwIndex); / 關(guān)閉事件return;【第九步】“享受”接收到的數(shù)據(jù)如果程序執(zhí)行到了這里,那么就說明一切正常,WSABUF結(jié)構(gòu)里面就存有我們WSARecv來的數(shù)據(jù)了,終于到了盡情享用成果的時(shí)候了!喝杯茶,休息一下吧_DataBuf.buf就是一個(gè)char*字符串指針,聽?wèi){你的處理吧,我就不多說了【第十步】同第五步一樣,在套接字上繼續(xù)投遞WSARecv請(qǐng)求,重復(fù)步驟 6 9 這樣一路作下來,我們終于可以從客戶端接收到數(shù)據(jù)了,但是回想起來,呀,這樣豈不是只能收到一次數(shù)據(jù),然后程序不就Over了?.-_-b 所以我們接下來不得不重復(fù)一遍第四步和第五步的工作,

31、再次在這個(gè)套接字上投遞另一個(gè)WSARecv請(qǐng)求,并且使整個(gè)過程循環(huán)起來,are u clear? 大家可以參考我的代碼,在這里就先不寫了,因?yàn)楦魑欢家欢ū任襰mart,領(lǐng)悟了關(guān)鍵所在以后,稍作思考就可以靈活變通了。五。 多客戶端情況的注意事項(xiàng) 完成了上面的循環(huán)以后,重疊模型就已經(jīng)基本上搭建好了80%了,為什么不是100%呢?因?yàn)樽屑?xì)一回想起來,呀,這樣豈不是只能連接一個(gè)客戶端?是的,如果只處理一個(gè)客戶端,那重疊模型就半點(diǎn)優(yōu)勢(shì)也沒有了,我們正是要使用重疊模型來處理多個(gè)客戶端。 所以我們不得不再對(duì)結(jié)構(gòu)作一些改動(dòng)。1首先,肯定是需要一個(gè)SOCKET數(shù)組 ,分別用來和每一個(gè)SOCKET通信其次,因?yàn)橹?/p>

32、疊模型中每一個(gè)SOCKET操作都是要“綁定”一個(gè)重疊結(jié)構(gòu)的,所以需要為每一個(gè)SOCKET操作搭配一個(gè)WSAOVERLAPPED結(jié)構(gòu),但是這樣說并不嚴(yán)格,因?yàn)槿绻恳粋€(gè)SOCKET同時(shí)只有一個(gè)操作,比如WSARecv,那么一個(gè)SOCKET就可以對(duì)應(yīng)一個(gè)WSAOVERLAPPED結(jié)構(gòu),但是如果一個(gè)SOCKET上會(huì)有WSARecv 和WSASend兩個(gè)操作,那么一個(gè)SOCKET肯定就要對(duì)應(yīng)兩個(gè)WSAOVERLAPPED結(jié)構(gòu),所以有多少個(gè)SOCKET操作就會(huì)有多少個(gè)WSAOVERLAPPED結(jié)構(gòu)。然后,同樣是為每一個(gè)WSAOVERLAPPED結(jié)構(gòu)都要搭配一個(gè)WSAEVENT事件,所以說有多少個(gè)SOCKET操作就應(yīng)該有多少個(gè)WSAOVERLAPPED結(jié)構(gòu),有多少個(gè)WSAOVERLAPPED結(jié)構(gòu)就應(yīng)該有多少個(gè)WSAEVENT事件,最好把SOCKET WSAOVERLAPPED WSAEVENT三者的關(guān)聯(lián)起來,到了關(guān)鍵時(shí)刻才會(huì)臨危不亂:)2 不得不分作兩個(gè)線程:一個(gè)用來循環(huán)監(jiān)聽端口,接收請(qǐng)求的連接,然后給在這個(gè)套接字上配合一個(gè)WSAOVERLAPPED結(jié)構(gòu)投遞第一個(gè)WSARecv請(qǐng)求,然后進(jìn)入第二個(gè)線

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論