IOCP WinSock2新函數(shù)打造高性能SOCKET池_第1頁(yè)
IOCP WinSock2新函數(shù)打造高性能SOCKET池_第2頁(yè)
IOCP WinSock2新函數(shù)打造高性能SOCKET池_第3頁(yè)
IOCP WinSock2新函數(shù)打造高性能SOCKET池_第4頁(yè)
IOCP WinSock2新函數(shù)打造高性能SOCKET池_第5頁(yè)
已閱讀5頁(yè),還剩15頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(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)在就接著展開(kāi)更深入的討論。首先這里要重點(diǎn)重申一下就是,SOCKET池主要指的是使用面向連接的協(xié)議的情況下,最常用的就是需要管理大量的TCP連接的時(shí)候。常見(jiàn)的就是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ù)的類,這里分解介紹下裝載的具體過(guò)程,要提醒的就是,凡是類里面演示了動(dòng)態(tài)裝載的函數(shù),最好都像那樣動(dòng)態(tài)載入,然后再調(diào)用。以免出現(xiàn)上網(wǎng)發(fā)帖跪求高手賜教為什么AcceptEx函數(shù)無(wú)法編譯通過(guò)等問(wèn)題??赐赀@篇文章詳細(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       /通常表示沒(méi)有正常的初始化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ǔ)的讀者來(lái)說(shuō)不是什么難事。 三、定義OVERLAPPED結(jié)構(gòu): 要想“IOCP”就要自定義OVER

17、LAPPED,這是徹底玩轉(zhuǎn)IOCP的不二法門(mén),可以這么說(shuō):“江湖上有多少種自定義的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)用者來(lái)說(shuō)是沒(méi)有意義的,但是很多時(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)回來(lái)即可。說(shuō)到這里一些C+基礎(chǔ)差一點(diǎn)的讀者估計(jì)已經(jīng)很頭暈了,更不知道我再說(shuō)什么,那么我就將好人做到底吧,來(lái)解釋下這個(gè)來(lái)龍去脈。首先就以我們將要使用的AcceptEx函數(shù)為例子看看它的原型吧(知道孫悟空的火眼金睛用來(lái)干嘛的嗎?就是用來(lái)看原型的,哈哈哈):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)指針,注意不是“老婆”拼音的縮寫(xiě)),本身這個(gè)參數(shù)的意思就是分配一塊OVERLAPPED大小的內(nèi)存,在IOCP調(diào)用方式下傳遞給AcceptEx函數(shù)用,調(diào)用者不用去關(guān)心里面的任何內(nèi)容,而在完成過(guò)程中(很多時(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è)*變成了指針的指針,并且前面的說(shuō)明很清楚Out!很明白了吧,不明白就真的Out了。這里就可以重新得到調(diào)用AcceptEx傳入的LPOVERLAPPED指針,也就是得到了這個(gè)“火車頭”,因?yàn)橹皇且粋€(gè)指針,并沒(méi)有詳細(xì)的限定能有多大,所以可以在火車頭的后面放很多東西。再仔細(xì)觀察GetQueuedCompletionStatus函

24、數(shù)的參數(shù),會(huì)發(fā)現(xiàn),這時(shí)只能知道一個(gè)IO操作結(jié)束了,但是究竟是哪個(gè)操作結(jié)束了,或者是哪個(gè)SOCKET句柄上的操作結(jié)束了,并沒(méi)有辦法知道。通常這個(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、緩沖中寫(xiě)入東西pMyOL->m_pBuf = pBuf;./其它的代碼AcceptEx(skServer, skClient,pBuf,0,/將接收緩沖置為0,令A(yù)cceptEx直接返回                      256,256,NULL,(LPOVERLAPPEDpMyOL;/注意最后這個(gè)強(qiáng)制類型轉(zhuǎn)換     &#

30、160;  在完成過(guò)程回調(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              /又見(jiàn)死循環(huán) 呵呵呵                     BOOL bRet = GetQueuedCompletionStatus(        

33、                    pThis->m_IOCP,&dwBytesTrans,&dwPerData,                      

34、60;     &lpOverlapped,INFINITE;                     if( NULL = lpOverlapped                 

35、0;    /沒(méi)有真正的完成                            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)來(lái)了 SOCKET句柄就是 pMyOL->m_skClient    break;. /end while.       /end fun 至此,關(guān)于這個(gè)“火車頭”如何使用,應(yīng)該是看明白了,其實(shí)就是從函數(shù)傳入,又由函數(shù)返回。只不過(guò)其間可能已經(jīng)轉(zhuǎn)換了線程環(huán)境,是不

39、同的線程了。這里再補(bǔ)充一個(gè)AcceptEx容易被遺漏的一個(gè)細(xì)節(jié)問(wèn)題,那就是在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;這樣來(lái)得到連入的客戶端地址,以及連入的服務(wù)端地址

42、,通常這個(gè)地址可以和這個(gè)客戶端的SOCKET綁定在一起用map或hash表保存,方便查詢,就不用再調(diào)用那個(gè)getpeername得到客戶端的地址了。要注意的是GetAcceptExSockaddrs也是一個(gè)WinSock2擴(kuò)展函數(shù),專門(mén)配合AcceptEx使用的,需要像AcceptEx那樣動(dòng)態(tài)載入一下,然后再調(diào)用,詳情請(qǐng)見(jiàn)前一篇文章中的CGRSMsSockFun類。至此AcceptEx算討論完整了,OVERLAPPED的派生定義也講完了,讓我們繼續(xù)下一步。 四、編寫(xiě)線程池回調(diào)函數(shù): 在討論擴(kuò)展定義OVERLAPPED結(jié)構(gòu)體時(shí),給出了非線程池版的線程函數(shù)的大概框架,也就是傳統(tǒng)

43、IOCP使用的自建線程使用方式,這種方式要自己創(chuàng)建完成端口句柄,自己將SOCKET句柄綁定到完成端口,這里就不在贅述,主要介紹下調(diào)用BindIoCompletionCallback函數(shù)時(shí),應(yīng)如何編寫(xiě)這個(gè)線程池的回調(diào)函數(shù),其實(shí)它與前面那個(gè)線程函數(shù)是很類似的。先來(lái)看看回調(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ù)就是說(shuō)這次IO操作一共完成了多少字節(jié)的數(shù)據(jù)傳輸任務(wù),這個(gè)字段有個(gè)特殊含義,如果你發(fā)現(xiàn)一個(gè)Recv操作結(jié)束了,并且這個(gè)參數(shù)為0,那么就是說(shuō),客戶端斷開(kāi)了連接(注意針對(duì)的是TCP方式,整個(gè)SOCKET池就是為T(mén)CP方式設(shè)計(jì)的)。如果這個(gè)情況發(fā)生了,在SOCKET池中就該回收這個(gè)SOCKET句柄。第三個(gè)參數(shù)現(xiàn)在不用多說(shuō)了,立刻就知道怎么用它了。跟剛才調(diào)用GetQueuedCompletionStatus函數(shù)得到的指針是一個(gè)含義。下面就來(lái)看一個(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;             /沒(méi)有真正的完成                     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)來(lái)了 SOCKET句柄就是 pMyOL->m_skClient    break;.    

50、;   /end fun 看起來(lái)很簡(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è)問(wèn)題,正如在IOCP編程之“雙節(jié)棍”中提到的,這個(gè)函數(shù)執(zhí)行時(shí)間不要過(guò)長(zhǎng),否則會(huì)出現(xiàn)掉線啊,連接不進(jìn)來(lái)啊等等奇怪的事情。另一個(gè)要注意的問(wèn)題就是,這個(gè)函數(shù)最好套上結(jié)構(gòu)化異常處理,盡可能的多攔截和處理異常,防止系統(tǒng)線程池的線程因?yàn)槟阍愀獾幕卣{(diào)函

51、數(shù)而壯烈犧牲,如果加入了并發(fā)控制,還要注意防止死鎖,不然你的服務(wù)器會(huì)“死”的很難看。理論上來(lái)說(shuō),你盡可以把這個(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ù)的神奇就是不見(jiàn)了CreateIoCompletionPort的調(diào)用,不見(jiàn)了CreateThread

52、的調(diào)用,不見(jiàn)了GetQueuedCompletionStatus等等的調(diào)用,省去了n多繁瑣且容易出錯(cuò)的步驟,一個(gè)函數(shù)就全部搞定了。 五、服務(wù)端調(diào)用: 以上的所有步驟在完全理解后,最終讓我們看看SOCKET池如何實(shí)現(xiàn)之。1、按照傳統(tǒng),要先監(jiān)聽(tīng)到某個(gè)IP的指定端口上:SOCKADDR_IN    saServer = 0;/創(chuàng)建監(jiān)聽(tīng)SocketSOCKET skServer = :WSASocket(AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED;/把監(jiān)聽(tīng)SOCKET扔進(jìn)

53、線程池,這個(gè)可以省略               :BindIoCompletionCallback(HANDLEskServer,MyIOCPThread, 0;/必要時(shí)打開(kāi)SO_REUSEADDR屬性,重新綁定到這個(gè)監(jiān)聽(tīng)地址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)聽(tīng)所有本地IP的相同端口saServer.sin_port = htons(80;      /用80得永生:bind(skServer,(LPSOCKADDR&saServer,siz

55、eof(SOCKADDR_IN;/監(jiān)聽(tīng),隊(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ā)管理超過(guò)6w個(gè)以上的連接時(shí),怎么辦呢?那就再插塊網(wǎng)卡租個(gè)新的IP,然后再朝那個(gè)IP端綁定并監(jiān)

63、聽(tīng)即可。因?yàn)槭褂昧薎NADDR_ANY,所以一監(jiān)聽(tīng)就是所有本地IP的相同端口,如果服務(wù)器的IP有內(nèi)外網(wǎng)之分,為了安全和區(qū)別起見(jiàn)可以明確指定監(jiān)聽(tīng)哪個(gè)IP,單IP時(shí)就要注意本IP空閑端口的數(shù)量問(wèn)題了。 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īng)狀態(tài),等待下一個(gè)用戶連接進(jìn)來(lái),至此組建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展開(kāi)的,而創(chuàng)建操作就全部都在服務(wù)啟動(dòng)的瞬間完成,一次性投遞一定數(shù)量的SOCKET進(jìn)入SOCKET池即可,這個(gè)數(shù)量也就是

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝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ù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論