![IOCP WinSock2新函數(shù)打造高性能SOCKET池_第1頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/23/c8941941-69da-49e6-a7fd-ece4a15901b7/c8941941-69da-49e6-a7fd-ece4a15901b71.gif)
![IOCP WinSock2新函數(shù)打造高性能SOCKET池_第2頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/23/c8941941-69da-49e6-a7fd-ece4a15901b7/c8941941-69da-49e6-a7fd-ece4a15901b72.gif)
![IOCP WinSock2新函數(shù)打造高性能SOCKET池_第3頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/23/c8941941-69da-49e6-a7fd-ece4a15901b7/c8941941-69da-49e6-a7fd-ece4a15901b73.gif)
![IOCP WinSock2新函數(shù)打造高性能SOCKET池_第4頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/23/c8941941-69da-49e6-a7fd-ece4a15901b7/c8941941-69da-49e6-a7fd-ece4a15901b74.gif)
![IOCP WinSock2新函數(shù)打造高性能SOCKET池_第5頁(yè)](http://file3.renrendoc.com/fileroot_temp3/2022-1/23/c8941941-69da-49e6-a7fd-ece4a15901b7/c8941941-69da-49e6-a7fd-ece4a15901b75.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、IOCP+WinSock2新函數(shù)打造高性能SOCKET池默認(rèn)分類 2010-03-15 17:47:16 閱讀24 評(píng)論1 字號(hào):大中小 在前一篇文章WinSock2編程之打造完整的SOCKET池 中,介紹了WinSock2的一些新函數(shù),并重點(diǎn)詳細(xì)介紹了什么是SOCKET池,有了這個(gè)概念,現(xiàn)在就接著展開更深入的討論。首先這里要重點(diǎn)重申一下就是,SOCKET池主要指的是使用面向連接的協(xié)議的情況下,最常用的就是需要管理大量的TCP連接的時(shí)候。常見的就是Web服務(wù)器、FTP服務(wù)器等。下面就分步驟的詳細(xì)介紹如何最終實(shí)現(xiàn)SOCKET池。 一、WinSock2環(huán)境的初始化:
2、;要使用WinSock2就需要先初始化Socket2.0的環(huán)境,不廢話,上代碼:WSADATA wd = 0;int iError = WSAStartup(MAKEWORD(2,0, &wd;if( 0 != iError /出現(xiàn)錯(cuò)誤,最好跟蹤看下錯(cuò)誤碼是多少 return FALSE;if ( LOBYTE(lpwsaData->wVersion != 2 /非2.0以上環(huán)境 退出了事 可能是可憐的WinCE系統(tǒng) WSACleanu
3、p(; return FALSE;最后再不使用WinSock之后都要記得調(diào)用一下WSACleanup(這個(gè)函數(shù); 二、裝載WinSock2函數(shù): 上一篇文章中給出了一個(gè)裝載WinSock2函數(shù)的類,這里分解介紹下裝載的具體過程,要提醒的就是,凡是類里面演示了動(dòng)態(tài)裝載的函數(shù),最好都像那樣動(dòng)態(tài)載入,然后再調(diào)用。以免出現(xiàn)上網(wǎng)發(fā)帖跪求高手賜教為什么AcceptEx函數(shù)無法編譯通過等問題??赐赀@篇文章詳細(xì)你不會(huì)再去發(fā)帖找答案了,呵呵呵,好了,上代碼:/定義一個(gè)好用的載入函數(shù) 摘自CGRSMsSockFun 類BO
4、OL LoadWSAFun(GUID&funGuid,void*& pFun/本函數(shù)利用參數(shù)返回函數(shù)指針 DWORD dwBytes = 0; pFun = NULL; /隨便創(chuàng)建一個(gè)SOCKET供WSAIoctl使用 并不一定要像下面這樣創(chuàng)建 SOCKET skTemp = :WSASocke
5、t(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVE
6、RLAPPED; if(INVALID_SOCKET = skTemp /通常表示沒有正常的初始化WinSock環(huán)境 return FALSE; :WSA
7、Ioctl(skTemp, SIO_GET_EXTENSION_FUNCTION_POINTER, &funGuid,sizeof(funGuid,&pFun,
8、 sizeof(pFun, &dwBytes, NULL,NULL; :closesocket(skTemp; return NULL != pFun;/演示如何動(dòng)態(tài)載入AcceptEx函數(shù).LPFN_ACCEPTEX pfnAcceptEx; /首先聲明函數(shù)指針 GUID GuidAcceptEx = WSAID_ACCEPTEX;LoadWSAFun(GuidAcceptEx,(v
9、oid*&pfnAcceptEx; /載入./使用豐富的參數(shù)調(diào)用.pfnAcceptEx(sListenSocket,sAcceptSocket,lpOutputBuffer, dwReceiveDataLength,dwLocalAddressLength,dwRemoteAddressLength,lpdwBytesReceived,lpOverlapped;
10、; /或者: SOCKET skAccept = :WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,
11、60; NULL, 0,WSA_FLAG_OVERLAPPED; PVOID pBuf = ne
12、w BYTEsizeof(sockaddr_in + 16; pfnAcceptEx(skServer, skAccept,pBuf, 0,/將接收緩沖置為0,令A(yù)cceptEx直接返回,防止拒絕服務(wù)攻擊
13、 sizeof(sockaddr_in + 16, sizeof(sockaddr_in + 16, NULL,
14、0; (LPOVERLAPPEDpAcceptOL;. 以上是一個(gè)簡(jiǎn)單的演示,如何動(dòng)態(tài)載入一個(gè)WinSock2擴(kuò)展函數(shù),并調(diào)用之,其它函數(shù)的詳細(xì)例子可以看前一篇文章中CGRSMsSockFun類的實(shí)現(xiàn)部分。如果使用CGRSMsSockFun 類的話當(dāng)然更簡(jiǎn)單,像下面這樣調(diào)用即可: CGRSMsSo
15、ckFun MsSockFun; MsSockFun.AcceptEx(skServer, skAccept,pBuf, 0,/將接收緩沖置為0,令A(yù)cceptEx直接返回,防止拒絕服務(wù)攻擊 sizeof(sock
16、addr_in + 16, sizeof(sockaddr_in + 16, NULL, (LPOVERLAPPEDpAcceptOL;如果要使用這個(gè)類,那么需要一些修改,主要是異常處理部分,自己注釋掉,或者用其它異常代替掉即可,這個(gè)對(duì)于有基礎(chǔ)的讀者來說不是什么難事。 三、定義OVERLAPPED結(jié)構(gòu): 要想“IOCP”就要自定義OVER
17、LAPPED,這是徹底玩轉(zhuǎn)IOCP的不二法門,可以這么說:“江湖上有多少種自定義的OVERLAPPED派生結(jié)構(gòu)體,就有多少種IOCP的封裝!”O(jiān)VERLAPPED本身是Windows IOCP機(jī)制內(nèi)部需要的一個(gè)結(jié)構(gòu)體,主要用于記錄每個(gè)IO操作的“完成狀態(tài)”,其內(nèi)容對(duì)于調(diào)用者來說是沒有意義的,但是很多時(shí)候我們把它當(dāng)做一個(gè)“火車頭”,因?yàn)樗梢苑奖愕陌衙總€(gè)IO操作的相關(guān)數(shù)據(jù)簡(jiǎn)單的“從調(diào)用處運(yùn)輸?shù)酵瓿苫卣{(diào)函數(shù)中”,這是一個(gè)非常有用的特性,哪么如何讓這個(gè)火車頭發(fā)揮運(yùn)輸?shù)淖饔媚??其?shí)很簡(jiǎn)單:讓它成為一個(gè)自定義的更大結(jié)構(gòu)體的第一個(gè)成員。然后用強(qiáng)制類型轉(zhuǎn)換,將自定義的結(jié)構(gòu)體轉(zhuǎn)換成OVERLAPPED指針即可
18、。當(dāng)然不一定非要是新結(jié)構(gòu)體的第一個(gè)成員,也可以是任何第n個(gè)成員,這時(shí)使用VC頭文件中預(yù)定義的一個(gè)宏CONTAINING_RECORD再反轉(zhuǎn)回來即可。說到這里一些C+基礎(chǔ)差一點(diǎn)的讀者估計(jì)已經(jīng)很頭暈了,更不知道我再說什么,那么我就將好人做到底吧,來解釋下這個(gè)來龍去脈。首先就以我們將要使用的AcceptEx函數(shù)為例子看看它的原型吧(知道孫悟空的火眼金睛用來干嘛的嗎?就是用來看原型的,哈哈哈):BOOL AcceptEx( _in SOCKET sListenSocket,
19、; _in SOCKET sAcceptSocket, _in PVOID lpOutputBuffer, _in DWORD dwReceiveDataLength, _in
20、160; DWORD dwLocalAddressLength, _in DWORD dwRemoteAddressLength, _out LPDWORD lpdwBytesReceived, _in LPOVER
21、LAPPED lpOverlapped;注意最后一個(gè)參數(shù),是一個(gè)OVERLAPPED結(jié)構(gòu)體的指針(LP的意思是Long Pointer,即指向32位地址長(zhǎng)指針,注意不是“老婆”拼音的縮寫),本身這個(gè)參數(shù)的意思就是分配一塊OVERLAPPED大小的內(nèi)存,在IOCP調(diào)用方式下傳遞給AcceptEx函數(shù)用,調(diào)用者不用去關(guān)心里面的任何內(nèi)容,而在完成過程中(很多時(shí)候是另一個(gè)線程中的事情了),通常調(diào)用GetQueuedCompletionStatus函數(shù)后,會(huì)再次得到這個(gè)指針,接著讓我們也看看它的原型:BOOL WINAPI GetQueuedCompletionStatus( _in
22、0; HANDLE CompletionPort, _out LPDWORD lpNumberOfBytes, _out PULONG_PTR lpCompletionKey, _out
23、60; LPOVERLAPPED* lpOverlapped, _in DWORD dwMilliseconds;注意這里的LPOVERLAPPED多了一個(gè)*變成了指針的指針,并且前面的說明很清楚Out!很明白了吧,不明白就真的Out了。這里就可以重新得到調(diào)用AcceptEx傳入的LPOVERLAPPED指針,也就是得到了這個(gè)“火車頭”,因?yàn)橹皇且粋€(gè)指針,并沒有詳細(xì)的限定能有多大,所以可以在火車頭的后面放很多東西。再仔細(xì)觀察GetQueuedCompletionStatus函
24、數(shù)的參數(shù),會(huì)發(fā)現(xiàn),這時(shí)只能知道一個(gè)IO操作結(jié)束了,但是究竟是哪個(gè)操作結(jié)束了,或者是哪個(gè)SOCKET句柄上的操作結(jié)束了,并沒有辦法知道。通常這個(gè)信息非常重要,因?yàn)橹挥性贗O操作實(shí)際完成之后才能釋放發(fā)送或接收等操作的緩沖區(qū)。這些信息可以定義成如下的一個(gè)擴(kuò)展OVERLAPPED結(jié)構(gòu):struct MYOVERLAPPED OVERLAPPED m_ol; int
25、 m_iOpType; /操作類型 0=AcceptEx 1=DisconnectEx 2=ConnectEx 3=WSARecv等等 SOCKET m
26、_skServer; /服務(wù)端SOCKET SOCKET m_skClient; /客戶端SOCKET LPVOID m_pBuf;
27、0; /本次IO操作的緩沖指針 . &
28、#160; /其它需要的信息;使用時(shí):MYOVERLAPPED* pMyOL = new MYOVERLAPPED;ZeroMemory(pMyOL,sizeof(MYOVERLAPPED;pMyOL->m_iOpType = 0; /AcceptEx操作pMyOL->m_skServer = skServer;pMyOL->m_skClient = skClient;BYTE* pBuf = new BYTE256;/一個(gè)緩沖. /朝
29、緩沖中寫入東西pMyOL->m_pBuf = pBuf;./其它的代碼AcceptEx(skServer, skClient,pBuf,0,/將接收緩沖置為0,令A(yù)cceptEx直接返回 256,256,NULL,(LPOVERLAPPEDpMyOL;/注意最后這個(gè)強(qiáng)制類型轉(zhuǎn)換
30、160; 在完成過程回調(diào)線程函數(shù)中,這樣使用: UINT CALLBACK Client_IOCPThread(void* pParam /IOCP線程函數(shù) . DWORD dwBytesTra
31、ns = 0; DWORD dwPerData = 0; LPOVERLAPPED lpOverlapped = NULL; whi
32、le(1 /又見死循環(huán) 呵呵呵 BOOL bRet = GetQueuedCompletionStatus(
33、 pThis->m_IOCP,&dwBytesTrans,&dwPerData,
34、60; &lpOverlapped,INFINITE; if( NULL = lpOverlapped
35、0; /沒有真正的完成 SleepEx(20,TRUE;/故意置成可警告狀態(tài)
36、0; continue;
37、; /找回“火車頭”以及后面的所有東西 MYOVERLAPPED* pOL = CONTAINING_RECORD(lpOverlapped, MYOVERLAPPED, m_ol;
38、; switch(pOL->m_iOpTypecase 0: /AcceptEx結(jié)束/有鏈接進(jìn)來了 SOCKET句柄就是 pMyOL->m_skClient break;. /end while. /end fun 至此,關(guān)于這個(gè)“火車頭”如何使用,應(yīng)該是看明白了,其實(shí)就是從函數(shù)傳入,又由函數(shù)返回。只不過其間可能已經(jīng)轉(zhuǎn)換了線程環(huán)境,是不
39、同的線程了。這里再補(bǔ)充一個(gè)AcceptEx容易被遺漏的一個(gè)細(xì)節(jié)問題,那就是在AcceptEx完成返回之后,如下在那個(gè)連入的客戶端SOCKET上調(diào)用一下: int nRet = :setsockopt( pOL->m_skClient,SOL_SOCKET,SO_UPDATE_ACCEPT_CONTEXT,
40、 (char *&pOL->m_skServer,sizeof(SOCKET;這樣才可以繼續(xù)在這個(gè)代表客戶端連接的pOL->m_skClient上繼續(xù)調(diào)用WSARecv和WSASend。另外,在AcceptEx完成之后,通??梢杂茫篖PSOCKADDR addrHost = NULL; /服務(wù)端地址LPSOCKADDR addrClient = NULL; /客戶端地址in
41、t lenHost = 0;int lenClient = 0;GetAcceptExSockaddrs( pOL->m_pBuf,0,sizeof(sockaddr_in + 16,sizeof(sockaddr_in + 16, (LPSOCKADDR* &addrHost,&lenHost,(LPSOCKADDR* &addrClient,&lenClient;這樣來得到連入的客戶端地址,以及連入的服務(wù)端地址
42、,通常這個(gè)地址可以和這個(gè)客戶端的SOCKET綁定在一起用map或hash表保存,方便查詢,就不用再調(diào)用那個(gè)getpeername得到客戶端的地址了。要注意的是GetAcceptExSockaddrs也是一個(gè)WinSock2擴(kuò)展函數(shù),專門配合AcceptEx使用的,需要像AcceptEx那樣動(dòng)態(tài)載入一下,然后再調(diào)用,詳情請(qǐng)見前一篇文章中的CGRSMsSockFun類。至此AcceptEx算討論完整了,OVERLAPPED的派生定義也講完了,讓我們繼續(xù)下一步。 四、編寫線程池回調(diào)函數(shù): 在討論擴(kuò)展定義OVERLAPPED結(jié)構(gòu)體時(shí),給出了非線程池版的線程函數(shù)的大概框架,也就是傳統(tǒng)
43、IOCP使用的自建線程使用方式,這種方式要自己創(chuàng)建完成端口句柄,自己將SOCKET句柄綁定到完成端口,這里就不在贅述,主要介紹下調(diào)用BindIoCompletionCallback函數(shù)時(shí),應(yīng)如何編寫這個(gè)線程池的回調(diào)函數(shù),其實(shí)它與前面那個(gè)線程函數(shù)是很類似的。先來看看回調(diào)函數(shù)長(zhǎng)個(gè)什么樣子:VOID CALLBACK FileIOCompletionRoutine( in DWORD dwError
44、Code, in DWORD dwNumberOfBytesTransfered, in LPOVERLAPPED lpOverlapped;第一個(gè)參數(shù)就是一個(gè)錯(cuò)誤碼,如果是0恭喜你,操作一切
45、ok,如果有錯(cuò)也不要慌張,前一篇文章中已經(jīng)介紹了如何翻譯和看懂這個(gè)錯(cuò)誤碼。照著做就是了。第二個(gè)參數(shù)就是說這次IO操作一共完成了多少字節(jié)的數(shù)據(jù)傳輸任務(wù),這個(gè)字段有個(gè)特殊含義,如果你發(fā)現(xiàn)一個(gè)Recv操作結(jié)束了,并且這個(gè)參數(shù)為0,那么就是說,客戶端斷開了連接(注意針對(duì)的是TCP方式,整個(gè)SOCKET池就是為TCP方式設(shè)計(jì)的)。如果這個(gè)情況發(fā)生了,在SOCKET池中就該回收這個(gè)SOCKET句柄。第三個(gè)參數(shù)現(xiàn)在不用多說了,立刻就知道怎么用它了。跟剛才調(diào)用GetQueuedCompletionStatus函數(shù)得到的指針是一個(gè)含義。下面就來看一個(gè)實(shí)現(xiàn)這個(gè)回調(diào)的例子:VOID CALLBACK MyIOCPT
46、hread(DWORD dwErrorCode,DWORD dwBytesTrans,LPOVERLAPPED lpOverlapped /IOCP回調(diào)函數(shù) . if( NULL = lpOverlapped
47、60; /沒有真正的完成 SleepEx(20,TRUE;/故意置成可警告狀態(tài)
48、60; return; /找回“火車頭”以及后面的所有東西
49、 MYOVERLAPPED* pOL = CONTAINING_RECORD(lpOverlapped, MYOVERLAPPED, m_ol; switch(pOL->m_iOpTypecase 0: /AcceptEx結(jié)束/有鏈接進(jìn)來了 SOCKET句柄就是 pMyOL->m_skClient break;.
50、; /end fun 看起來很簡(jiǎn)單吧?好像少了什么?對(duì)了那個(gè)該死的循環(huán),這里不用了,因?yàn)檫@個(gè)是由線程池回調(diào)的一個(gè)函數(shù)而已,線程的活動(dòng)狀態(tài)完全由系統(tǒng)內(nèi)部控制,只管認(rèn)為只要有IO操作完成了,此函數(shù)就會(huì)被調(diào)用。這里關(guān)注的焦點(diǎn)就完全的放到了完成之后的操作上,而什么線程啊,完成端口句柄啊什么的就都不需要了(甚至可以忘記)。這里要注意一個(gè)問題,正如在IOCP編程之“雙節(jié)棍”中提到的,這個(gè)函數(shù)執(zhí)行時(shí)間不要過長(zhǎng),否則會(huì)出現(xiàn)掉線啊,連接不進(jìn)來啊等等奇怪的事情。另一個(gè)要注意的問題就是,這個(gè)函數(shù)最好套上結(jié)構(gòu)化異常處理,盡可能的多攔截和處理異常,防止系統(tǒng)線程池的線程因?yàn)槟阍愀獾幕卣{(diào)函
51、數(shù)而壯烈犧牲,如果加入了并發(fā)控制,還要注意防止死鎖,不然你的服務(wù)器會(huì)“死”的很難看。理論上來說,你盡可以把這個(gè)函數(shù)看做一個(gè)與線程池函數(shù)等價(jià)的函數(shù),只是他要盡可能的“短”(指執(zhí)行時(shí)間)而緊湊(結(jié)構(gòu)清晰少出錯(cuò))。最后,回調(diào)函數(shù)定義好了,就可以調(diào)用BindIoCompletionCallback函數(shù),將一個(gè)SOCKET句柄丟進(jìn)完成端口的線程池了:BindIoCompletionCallback(HANDLEskClient,MyIOCPThread,0;注意最后一個(gè)參數(shù)到目前為止,你就傳入0吧。這個(gè)函數(shù)的神奇就是不見了CreateIoCompletionPort的調(diào)用,不見了CreateThread
52、的調(diào)用,不見了GetQueuedCompletionStatus等等的調(diào)用,省去了n多繁瑣且容易出錯(cuò)的步驟,一個(gè)函數(shù)就全部搞定了。 五、服務(wù)端調(diào)用: 以上的所有步驟在完全理解后,最終讓我們看看SOCKET池如何實(shí)現(xiàn)之。1、按照傳統(tǒng),要先監(jiān)聽到某個(gè)IP的指定端口上:SOCKADDR_IN saServer = 0;/創(chuàng)建監(jiān)聽SocketSOCKET skServer = :WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED;/把監(jiān)聽SOCKET扔進(jìn)
53、線程池,這個(gè)可以省略 :BindIoCompletionCallback(HANDLEskServer,MyIOCPThread, 0;/必要時(shí)打開SO_REUSEADDR屬性,重新綁定到這個(gè)監(jiān)聽地址BOOL bReuse=TRUE;
54、160; :setsockopt(m_skServer,SOL_SOCKET,SO_REUSEADDR,(LPCSTR&bReuse,sizeof(BOOL;saServer.sin_family = AF_INET;saServer.sin_addr.s_addr = INADDR_ANY; / INADDR_ANY這個(gè)值的魅力是監(jiān)聽所有本地IP的相同端口saServer.sin_port = htons(80; /用80得永生:bind(skServer,(LPSOCKADDR&saServer,siz
55、eof(SOCKADDR_IN;/監(jiān)聽,隊(duì)列長(zhǎng)為默認(rèn)最大連接SOMAXCONNlisten(skServer, SOMAXCONN; 2、就是發(fā)出一大堆的AcceptEx調(diào)用:for(UINT i = 0; i < 1000; i+/調(diào)用1000次/創(chuàng)建與客戶端通訊的SOCKET,注意SOCKET的創(chuàng)建方式skAccept = :WSASocket(AF_INET,
56、 SOCK_STREAM,
57、; IPPROTO_TCP,
58、60; NULL,
59、160; 0,
60、; WSA_FLAG_OVERLAPPED;/丟進(jìn)線程池中BindIoCompletionCallback(HANDLEskAccept ,MyIOCPThread,0;/創(chuàng)建一個(gè)自定義的OVERLAPPED擴(kuò)展結(jié)構(gòu),使用IOCP方式調(diào)用pMyOL= new MYOVERLAPPED;pMyOL->m_iOpType = 0; /AcceptEx操作p
61、MyOL->m_skServer = skServer;pMyOL->m_skClient = skClient;BYTE* pBuf = new BYTE256;/一個(gè)緩沖ZeroMemory(pBuf,256*sizeof(BYTE;pMyOL->m_pBuf = pBuf;/發(fā)出AcceptEx調(diào)用/注意將AcceptEx函數(shù)接收連接數(shù)據(jù)緩沖的大小設(shè)定成了0/這將導(dǎo)致此函數(shù)立即返回,雖然與不設(shè)定成0的方式而言,/這導(dǎo)致了一個(gè)較低下的效率,但是這樣提高了安全性/所以這種效率犧牲是必須的AcceptEx(skServer, skAccept,pBuf,
62、0; 0,/將接收緩沖置為0,令A(yù)cceptEx直接返回,防止拒絕服務(wù)攻擊 256,256,NULL,(LPOVERLAPPEDpMyOL; 這樣就有1000個(gè)AcceptEx在提前等著客戶端的連接了,即使1000個(gè)并發(fā)連接也不怕了,當(dāng)然如果再BT點(diǎn)那么就放1w個(gè),什么你要放2w個(gè)?那就要看看你的這個(gè)IP段的端口還夠不夠了,還有你的系統(tǒng)內(nèi)存夠不夠用。一定要注意同一個(gè)IP地址上理論上端口最大值是65535,也就是6w多個(gè),這個(gè)要合理的分派,如果并發(fā)管理超過6w個(gè)以上的連接時(shí),怎么辦呢?那就再插塊網(wǎng)卡租個(gè)新的IP,然后再朝那個(gè)IP端綁定并監(jiān)
63、聽即可。因?yàn)槭褂昧薎NADDR_ANY,所以一監(jiān)聽就是所有本地IP的相同端口,如果服務(wù)器的IP有內(nèi)外網(wǎng)之分,為了安全和區(qū)別起見可以明確指定監(jiān)聽哪個(gè)IP,單IP時(shí)就要注意本IP空閑端口的數(shù)量問題了。 3、AcceptEx返回后,也就是線程函數(shù)中,判定是AcceptEx操作返回后,首先需要的調(diào)用就是:GetAcceptExSockaddrs(pBuf,0,sizeof(sockaddr_in + 16, sizeof(sockaddr_in + 16,(LPSOCKADDR* &addrHost,&
64、lenHost, (LPSOCKADDR* &addrClient,&lenClient;int nRet = :setsockopt(pOL->m_skClient, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,(char *&m_skServer,sizeof(m_skServer;之后就可以WSASend或者WSARecv了。 &
65、#160; 4、這些調(diào)用完后,就可以在這個(gè)m_skClient上收發(fā)數(shù)據(jù)了,如果收發(fā)數(shù)據(jù)結(jié)束或者IO錯(cuò)誤,那么就回收SOCKET進(jìn)入SOCKET池: DisconnectEx(m_skClient,&pData->m_ol, TF_REUSE_SOCKET, 0; 5、當(dāng)DisconnectEx函數(shù)完成操作之后,在回調(diào)的線程函數(shù)中,像下面這樣重新讓這個(gè)SOCKET進(jìn)入監(jiān)聽狀態(tài),等待下一個(gè)用戶連接進(jìn)來,至此組建SOCKET池的目的就真正達(dá)到
66、了:/創(chuàng)建一個(gè)自定義的OVERLAPPED擴(kuò)展結(jié)構(gòu),使用IOCP方式調(diào)用pMyOL= new MYOVERLAPPED;pMyOL->m_iOpType = 0; /AcceptEx操作pMyOL->m_skServer = skServer;pMyOL->m_skClient = skClient;BYTE* pBuf = new BYTE256;/一個(gè)緩沖ZeroMemory(pBuf,256*sizeof(BYTE;pMyOL->m_pBuf = pBuf;AcceptEx(skS
67、erver, skClient,pBuf , 0,256,256,NULL, (LPOVERLAPPEDpMyOL;/注意在這個(gè)SOCKET被重新利用后,后面的再次捆綁到完成端口的操作會(huì)返回一個(gè)已設(shè)置/的錯(cuò)誤,這個(gè)錯(cuò)誤直接被忽略即可 :BindIoCompletionCallback(HANDLEskClient,Server_IOCPThread, 0; 至此服務(wù)端的線程池就算搭建完成了,這個(gè)SOCKET池也就是圍繞AcceptEx和DisconnectEx展開的,而創(chuàng)建操作就全部都在服務(wù)啟動(dòng)的瞬間完成,一次性投遞一定數(shù)量的SOCKET進(jìn)入SOCKET池即可,這個(gè)數(shù)量也就是
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 裝修進(jìn)度款支付合同
- 藥品冷鏈運(yùn)輸保密合同
- 商業(yè)空間裝修施工合同范本
- 包包購(gòu)銷合同
- 咨詢服務(wù)合同終止協(xié)議書年
- 互聯(lián)網(wǎng)廣告投放策略與實(shí)踐案例
- 建筑項(xiàng)目居間合同
- 出租打印機(jī)合同年
- 圖書購(gòu)銷合同范例
- 工程管理咨詢合同
- 2 找春天 公開課一等獎(jiǎng)創(chuàng)新教學(xué)設(shè)計(jì)
- 2025年江蘇護(hù)理職業(yè)學(xué)院高職單招語(yǔ)文2018-2024歷年參考題庫(kù)頻考點(diǎn)含答案解析
- 2025年江蘇南京水務(wù)集團(tuán)有限公司招聘筆試參考題庫(kù)含答案解析
- 護(hù)理人文知識(shí)培訓(xùn)課件
- 建筑工程施工安全管理課件
- 2025年春新人教版數(shù)學(xué)七年級(jí)下冊(cè)教學(xué)課件 7.2.3 平行線的性質(zhì)(第1課時(shí))
- 安徽省合肥市2025年高三第一次教學(xué)質(zhì)量檢測(cè)地理試題(含答案)
- 2025年上半年畢節(jié)市威寧自治縣事業(yè)單位招考考試(443名)易考易錯(cuò)模擬試題(共500題)試卷后附參考答案
- 高考語(yǔ)文古詩(shī)詞必背重點(diǎn)提綱
- 超星爾雅學(xué)習(xí)通《大學(xué)生心理健康教育(蘭州大學(xué)版)》章節(jié)測(cè)試含答案
- 2020譯林版高中英語(yǔ)選擇性必修二單詞默寫表
評(píng)論
0/150
提交評(píng)論