版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 專用辦公學(xué)習(xí)文具用品批量采購(gòu)協(xié)議版B版
- 2025年度二手房產(chǎn)權(quán)過(guò)戶服務(wù)合同4篇
- 2025年度生態(tài)農(nóng)業(yè)園區(qū)場(chǎng)地租用及農(nóng)產(chǎn)品銷售服務(wù)合同4篇
- 專業(yè)布料購(gòu)入?yún)f(xié)議2024版格式
- 2025年度拆遷施工工程監(jiān)理合同規(guī)范文本4篇
- 2025年度新型建筑材料采購(gòu)合作服務(wù)協(xié)議4篇
- 二零二五年度綠色能源廠房產(chǎn)權(quán)移交協(xié)議3篇
- 2025年度出境旅游產(chǎn)品研發(fā)與推廣合作協(xié)議2篇
- 2025年度新型材料研發(fā)廠房租賃及成果轉(zhuǎn)化合同2篇
- 2025年度智能倉(cāng)儲(chǔ)場(chǎng)地租賃及安全防護(hù)協(xié)議范本4篇
- 食堂油鍋起火演練方案及流程
- 《呼吸衰竭的治療》
- 有余數(shù)的除法算式300題
- 2024年度醫(yī)患溝通課件
- 2024年中考政治總復(fù)習(xí)初中道德與法治知識(shí)點(diǎn)總結(jié)(重點(diǎn)標(biāo)記版)
- 2024年手術(shù)室的應(yīng)急預(yù)案
- 五年級(jí)上冊(cè)小數(shù)除法豎式計(jì)算練習(xí)300題及答案
- 【外資便利店在我國(guó)的經(jīng)營(yíng)策略分析案例:以日本羅森便利店為例11000字(論文)】
- 6061鋁合金退火工藝
- 教師職業(yè)素養(yǎng)與職業(yè)發(fā)展規(guī)劃
- 語(yǔ)言規(guī)劃講義
評(píng)論
0/150
提交評(píng)論