• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            山寨:不是最好的,是最適合我們的!歡迎體驗(yàn)山寨 中文版MSDN

            Blog @ Blog

            當(dāng)華美的葉片落盡,生命的脈絡(luò)才歷歷可見。 -- 聶魯達(dá)

            常用鏈接

            統(tǒng)計(jì)

            積分與排名

            BBS

            Blog

            Web

            最新評(píng)論

            端口技術(shù) GetOverlappedResult [轉(zhuǎn)]

            以一個(gè)文件傳輸服務(wù)端為例,在我的機(jī)器上它只起兩個(gè)線程就可以為很多個(gè)個(gè)客戶端同時(shí)提供文件下載服務(wù),程序的性能會(huì)隨機(jī)器內(nèi)CPU個(gè)數(shù)的增加而線性增長,我盡可能做到使它清晰易懂,雖然程序很小卻用到了NT 5的一些新特性,重疊IO,完成端口以及線程池,基于這種模型的服務(wù)端程序應(yīng)該是NT系統(tǒng)上性能最好的了.

            首先.做為完成端口的基礎(chǔ),我們應(yīng)該理解重疊IO,這需要你已經(jīng)理解了內(nèi)核對(duì)象及操作系統(tǒng)的一些概念概念,什么是信號(hào)/非信號(hào)態(tài),什么是等待函數(shù),什么是成功等待的副作用,什么是線程掛起等,如果這些概令還沒有理解,你應(yīng)該先看一下Windows 核心編程中的相關(guān)內(nèi)容.如果已經(jīng)理解這些,那么重疊IO對(duì)你來說并不難.

            你可以這樣認(rèn)為重疊IO,現(xiàn)在你已經(jīng)進(jìn)入一個(gè)服務(wù)器/客戶機(jī)環(huán)境,請(qǐng)不要混淆概念,這里的服務(wù)器是指操作系統(tǒng),而客戶機(jī)是指你的程序(它進(jìn)行IO操作),是當(dāng)你進(jìn)行IO操作(send,recv,writefile,readfile….)時(shí)你發(fā)送一個(gè)IO請(qǐng)求給服務(wù)器(操作系統(tǒng)),由服務(wù)器來完成你需要的操作,然后你什么事都沒有了,當(dāng)服務(wù)器完成IO請(qǐng)求時(shí)它會(huì)通知你,當(dāng)然在這期間你可以做任何事,一個(gè)常用的技巧是在發(fā)送重疊IO請(qǐng)求后,程序在一個(gè)循環(huán)中一邊調(diào)用PeekMessage,TranslateMessage和DispatchMessage更新界面,同時(shí)調(diào)用 GetOverlappedResult等待服務(wù)器完成IO操作,更高效一點(diǎn)的做法是使用IO完成例程來處理服務(wù)器(操作系統(tǒng))返回的結(jié)果,但并不是每個(gè)支持重疊IO操作的函數(shù)都支持完成例程如TransmitFile函數(shù).

            例1.一次重疊寫操作過程(GetOverlappedResult方法):
            1.填寫一個(gè)OVERLAPPED結(jié)構(gòu)
            2.進(jìn)行一次寫操作,并指定重疊操作參數(shù)(上面的OVERLAPPED結(jié)構(gòu)變量的指針)
            3.做其它事(如更新界面)
            4.GetOverlappedResult取操作結(jié)果
            5.如果IO請(qǐng)求沒有完成,并且沒有出錯(cuò)則回到3
            6.處理IO操作結(jié)果

            例2.一次重疊寫操作過程(完成例程方法):
            1.填寫一個(gè)OVERLAPPED結(jié)構(gòu)
            2.進(jìn)行一次寫操作,并指定重疊操作參數(shù)(上面的OVERLAPPED結(jié)構(gòu)變量的指針),并指定完成例程
            3.做其它事(如更新界面)
            4.當(dāng)完成例程被調(diào)用說明IO操作已經(jīng)完成或出錯(cuò),現(xiàn)在可以對(duì)操作結(jié)果進(jìn)行處理了

            如果你已經(jīng)理解上面的概念,就已經(jīng)很接近IO完成端口了,當(dāng)然這只是很常規(guī)的重疊操作它已經(jīng)非常高效,但如果再結(jié)合多線程對(duì)一個(gè)File或是Socket進(jìn)行重疊IO操作就會(huì)非常復(fù)雜,通常程序員很難把握這種復(fù)雜度.完成端口可以說就是為了充分發(fā)揮多線程和重疊IO操作相結(jié)合的性能而設(shè)計(jì)的.很多人都說它復(fù)雜,其實(shí)如果你自己實(shí)現(xiàn)一個(gè)多線程的對(duì)一個(gè)File或是Socket進(jìn)行重疊IO操作的程序(注意是多個(gè)線程對(duì)一個(gè)HANDLE或SOCKET進(jìn)行重疊 IO操作,而不是啟一個(gè)線程對(duì)一個(gè)HANDLE進(jìn)行重疊IO操作)就會(huì)發(fā)現(xiàn)完成端口實(shí)際上簡化了多線程里使用重疊IO的復(fù)雜度,并且性能更高,性能高在哪?下面進(jìn)行說明.

            我們可能寫過這樣的服務(wù)端程序:

            例3.主程序:
            1.監(jiān)聽一個(gè)端口
            2.等待連接
            3.當(dāng)有連接來時(shí)
            4.啟一個(gè)線程對(duì)這個(gè)客戶端進(jìn)行處理
            5.回到2

            服務(wù)線程:
            1.讀客戶端請(qǐng)求
            2.如果客戶端不再有請(qǐng)求,執(zhí)行6
            3.處理請(qǐng)求
            4.返回操作結(jié)果
            5.回到1
            6.退出線程

            這是一種最簡單的網(wǎng)絡(luò)服務(wù)器模型,我們把它優(yōu)化一下

            例4.主程序:
            1.開一個(gè)線程池,里面有機(jī)器能承受的最大線程數(shù)個(gè)線程,線程都處于掛起(suspend)狀態(tài)
            1.監(jiān)聽一個(gè)端口
            2.等待連接
            3.當(dāng)有連接來時(shí)
            4.從線程池里Resume一個(gè)線程對(duì)這個(gè)客戶端進(jìn)行處理
            5.回到2

            服務(wù)線程與例3模型里的相同,只是當(dāng)線程處理完客戶端所有請(qǐng)求后,不是退出而是回到線程池,再次掛起讓出CPU時(shí)間,并等待為下一個(gè)客戶機(jī)服務(wù).當(dāng)然在此期間線程會(huì)因?yàn)镮O操作(服務(wù)線程的第1,5操作,也許還有其它阻塞操作)掛起自己,但不會(huì)回到線程池,也就是說它一次只能為一個(gè)客戶端服務(wù).

            這可能是你能想到的最高效的服務(wù)端模型了吧!它與第一個(gè)服務(wù)端模型相比少了很多個(gè)用戶態(tài)到內(nèi)核態(tài)的CONTEXT Switch,反映也更加快速,也許你可能覺得這很微不足道,這說明你缺少對(duì)大規(guī)模高性能服務(wù)器程序(比如網(wǎng)游服務(wù)端)的認(rèn)識(shí),如果你的服務(wù)端程序要對(duì)幾千萬個(gè)客戶端進(jìn)行服務(wù)呢?這也是微軟Windows NT開發(fā)組在NT 5以上的系統(tǒng)中添加線程池的原因.

            思考一下什么樣的模型可以讓一個(gè)線程為多個(gè)客戶端服務(wù)呢!那就要跳出每來一個(gè)連接啟線程為其服務(wù)的固定思維模式,我們把線程服務(wù)的最小單元分割為單獨(dú)的讀或?qū)懖僮?注意是讀或?qū)懖皇亲x和寫),而不是一個(gè)客戶端從連接到斷開期間的所有讀寫操作.每個(gè)線程都使用重疊IO進(jìn)行讀寫操作,投遞了讀寫請(qǐng)求后線程回到線程池,等待為其它客戶機(jī)服務(wù),當(dāng)操作完成或出錯(cuò)時(shí)再回來處理操作結(jié)果,然后再回到線程池.

            看看這樣的服務(wù)器模型:
            例5.主程序:
            1.開一個(gè)線程池,里面有機(jī)器內(nèi)CPU個(gè)數(shù)兩倍的線程,線程都處于掛起(suspend)狀態(tài),它們?cè)诙嫉忍幚硪淮沃丿BIO操作的完成結(jié)果
            1.監(jiān)聽一個(gè)端口
            2.等待連接
            3.當(dāng)有連接來時(shí)
            4.投遞一個(gè)重疊讀操作讀取命令
            5.回到2

            服務(wù)線程:
            1.如果讀完成,則處理讀取的內(nèi)容(如HTTP GET命令),否則執(zhí)行3
            2.投遞一個(gè)重疊寫操作(如返回HTTP GET命令需要的網(wǎng)頁)
            3.如果是一個(gè)寫操作完成,可以再投遞一個(gè)重疊讀操作,讀取客戶機(jī)的下一個(gè)請(qǐng)求,或者是關(guān)閉連接(如HTTP協(xié)議里每發(fā)完一個(gè)網(wǎng)頁就斷開)
            4.取得下一個(gè)重疊IO操作結(jié)果,如果IO操作沒有完成或沒有IO操作則回到線程池

            假設(shè)這是一個(gè)WEB服務(wù)器程序,可以看到工作者線程是以讀或?qū)憺樽钚〉墓ぷ鲉卧\(yùn)行的,在主程序里面進(jìn)行了一次重疊讀操作

            當(dāng)讀操作完成時(shí)一個(gè)線程池中的一個(gè)工作者線程被激活取得了操作結(jié)果,處理GET或POST命令,然后發(fā)送一個(gè)網(wǎng)頁內(nèi)容,發(fā)送也是一個(gè)重疊操作,然后處理對(duì)其它客戶機(jī)的IO操作結(jié)果,如果沒有其它的東西需要處理時(shí)回到線程池等待.可以看到使用這種模型發(fā)送和接收可以是也可以不是一個(gè)線程.

            當(dāng)發(fā)送操作完成時(shí),線程池中的一個(gè)工作者線程池激活,它關(guān)閉連接(HTTP協(xié)議),然后處理其它的IO操作結(jié)果,如果沒有其它的東西需要處理時(shí)回到線程池等待.

            看看在這樣的模型中一個(gè)線程怎么為多個(gè)客戶端服務(wù),同樣是模擬一個(gè)WEB服務(wù)器例子:

            假如現(xiàn)在系統(tǒng)中有兩個(gè)線程,ThreadA,ThreadB它們?cè)诙嫉忍幚硪淮沃丿BIO操作的完成結(jié)果

            當(dāng)一個(gè)客戶機(jī)ClientA連接來時(shí)主程序投遞一個(gè)重疊讀操作,然后等待下一個(gè)客戶機(jī)連接,當(dāng)讀操作完成時(shí)ThreadA被激活,它收到一個(gè)HTTP GET命令,然后ThreadA使用重疊寫操作發(fā)送一個(gè)網(wǎng)頁給ClientA,然后立即回到線程池等待處理下一個(gè)IO操作結(jié)果,這時(shí)發(fā)送操作還沒有完成, 又有一個(gè)客戶機(jī)ClientB連接來,主程序再投遞一個(gè)重疊讀操作,當(dāng)讀操作完成時(shí)ThreadA(當(dāng)然也可能是ThreadB)再次被激活,它重復(fù)同樣步驟,收到一個(gè)GET命令,使用重疊寫操作發(fā)送一個(gè)網(wǎng)頁給ClientB,這次它沒有來得及回到線程池時(shí),又有一個(gè)連接ClientC連入,主程序再投遞一個(gè)重疊讀操作,讀操作完成時(shí)ThreadB被激活(因?yàn)門hreadA還沒有回到線程池)它收到一個(gè)HTTP GET命令,然后ThreadB使用重疊寫操作發(fā)送一個(gè)網(wǎng)頁給ClientC,然后ThreadB回到線程池,這時(shí)ThreadA也回到了線程池.

            可以想象現(xiàn)在有三個(gè)掛起的發(fā)送操作分別是ThreadA發(fā)送給ClientA和ClientB的網(wǎng)頁,以及ThreadB發(fā)送給ClientC的網(wǎng)頁,它們由操作系統(tǒng)內(nèi)核來處理.ThreadA和ThreadB現(xiàn)在已經(jīng)回到線程池,可以繼續(xù)為其它任何客戶端服務(wù).

            當(dāng)對(duì)ClientA的重疊寫操作已經(jīng)完成,ThreadA(也可以是ThreadB)又被激活,它關(guān)閉與ClientA連接,但還沒有回到線程池,與此同時(shí)發(fā)送給ClientB的重疊寫操作也完成,ThreadB被激活(因?yàn)門hreadA還沒有回到線程池)它關(guān)閉與ClientB的連接,然后回到線程池, 這時(shí)ClientC的寫操作也完成,ThreadB再次被激活(因?yàn)門hreadA還是沒有回到線程池),它再關(guān)閉與ClientC的連接,這時(shí) ThreadA回到線程池,ThreadB也回到線程池.這時(shí)對(duì)三個(gè)客戶端的服務(wù)全部完成.可以看到在整個(gè)服務(wù)過程中,”建立連接”,”讀數(shù)據(jù)”,”寫數(shù)據(jù)”和”關(guān)閉連接”等操作是邏輯上連續(xù)而實(shí)際上分開的.

            到現(xiàn)在為止兩個(gè)線程處理了三次讀操作和三次寫操作,在這些讀寫操作過程中所出現(xiàn)的狀態(tài)機(jī)(state machine)是比較復(fù)雜的,我們模擬的是經(jīng)過我簡化過的,實(shí)際上的狀態(tài)要比這個(gè)還要復(fù)雜很多,然而這樣的服務(wù)端模型在客戶端請(qǐng)求越多時(shí)與前兩個(gè)模型相比的性能越高.而使用完成端口我們可以很容易實(shí)現(xiàn)這樣的服務(wù)器模型.

            微軟的IIS WEB服務(wù)器就是使用這樣的服務(wù)端模型,很多人說什么阿帕奇服務(wù)器比IIS的性能好什么什么的我表示懷疑,除非阿帕奇服務(wù)器可以將線程分割成,為更小的單元服務(wù),我覺得不太可能!這種完成端口模型已經(jīng)將單個(gè)讀或?qū)懖僮髯鳛樽钚〉姆?wù)單元,我覺得在相同機(jī)器配置的情況下IIS的性能要遠(yuǎn)遠(yuǎn)高于其它WEB服務(wù)器,這也是從實(shí)現(xiàn)機(jī)理上來分析的,如果出現(xiàn)性能上的差別可能是在不同的操作系統(tǒng)上,也許Linux的內(nèi)核比Windows的要好,有人真的研究過嗎?還是大家一起在炒作啊.

            對(duì)于狀態(tài)機(jī)概念,在很多方面都用到,TCPIP中有,編譯原理中有,OpengGL中有等等,我的離散數(shù)學(xué)不好 (我是會(huì)計(jì)專業(yè)不學(xué)這個(gè)),不過還是搞懂了些,我想如果你多花些時(shí)間看,還是可以搞懂的.最后是一個(gè)簡單的文件傳輸服務(wù)器程序代碼,只用了兩個(gè)線程(我的機(jī)器里只有一塊CPU)就可以服務(wù)多個(gè)客戶端.我調(diào)試時(shí)用它同時(shí)為6個(gè)nc客戶端提供文件下載服務(wù)都沒有問題,當(dāng)然更多也不會(huì)有問題,只是略為使用了一下 NT 5的線程池和完成端口技術(shù)就可以有這樣高的性能,更不用說IIS的性能咯!

            希望大家不要陷在這個(gè)程序的框架中,Ctrl+C, Ctrl+V沒有什么意義,要理解它的實(shí)質(zhì).程序使用Visual C++ 6.0 SP5+2003 Platform SDK編譯通過,在Windows XP Professional下調(diào)試運(yùn)行通過.程序運(yùn)行的最低要求是Windows 2000操作系統(tǒng).

            /********************************************************************
            created:??? 2005/12/24
            created:??? 24:12:2005?? 20:25
            modified:??? 2005/12/24
            filename:???? d:\vcwork\iocomp\iocomp.cpp
            file path:??? d:\vcwork\iocomp
            file base:??? iocomp
            file ext:??? cpp
            author:??????? kruglinski(kruglinski_at_gmail_dot_com)

            purpose:??? 利用完成端口技術(shù)實(shí)現(xiàn)的高性能文件下載服務(wù)程序
            ********************************************************************
            */


            #define _WIN32_WINNT??? 0×0500

            #include 
            <cstdlib>
            #include 
            <clocale>
            #include 
            <ctime>
            #include 
            <iostream>//一使用輸入輸出流程序頓時(shí)增大70K
            #include <vector>
            #include 
            <algorithm>
            #include 
            <winsock2.h>
            #include 
            <mswsock.h>

            using namespace std;

            #pragma comment(lib,”ws2_32.lib”)
            #pragma comment(lib,”mswsock.lib”)

            const int MAX_BUFFER_SIZE=1024;
            const int PRE_SEND_SIZE=1024;
            const int QUIT_TIME_OUT=3000;
            const int PRE_DOT_TIMER=QUIT_TIME_OUT/80;

            typedef 
            enum{IoTransFile,IoSend,IoRecv,IoQuit} IO_TYPE;

            typedef 
            struct
            {
            SOCKET hSocket;
            SOCKADDR_IN ClientAddr;
            }
            PRE_SOCKET_DATA,*PPRE_SOCKET_DATA;

            typedef 
            struct
            {
            OVERLAPPED
            ??? oa;
            WSABUF
            ??????? DataBuf;
            char??????? Buffer[MAX_BUFFER_SIZE];
            IO_TYPE
            ??????? IoType;
            }
            PRE_IO_DATA,*PPRE_IO_DATA;

            typedef vector
            <PPRE_SOCKET_DATA>??? SocketDataVector;
            typedef vector
            <PPRE_IO_DATA>??????? IoDataVector;

            SocketDataVector
            ??? gSockDataVec;
            IoDataVector
            ??????? gIoDataVec;

            CRITICAL_SECTION
            ??? csProtection;

            char* TimeNow(void)
            {
            time_t t
            =time(NULL);
            tm 
            *localtm=localtime(&t);
            static char timemsg[512]={0};

            strftime(timemsg,
            512,”%Z: %%%X,%Y”,localtm);
            return timemsg;
            }


            BOOL TransFile(PPRE_IO_DATA pIoData,PPRE_SOCKET_DATA pSocketData,DWORD dwNameLen)
            {
            //這一句是為nc做的,你可以修改它
            pIoData->Buffer[dwNameLen-1]=”;

            HANDLE hFile
            =CreateFile(pIoData->Buffer,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
            BOOL bRet
            =FALSE;

            if(hFile!=INVALID_HANDLE_VALUE)
            {
            cout
            <<”Transmit File “<<pIoData->Buffer<<” to client”<<endl;
            pIoData
            ->IoType=IoTransFile;
            memset(
            &pIoData->oa,0,sizeof(OVERLAPPED));
            *reinterpret_cast<HANDLE*>(pIoData->Buffer)=hFile;
            TransmitFile(pSocketData
            ->hSocket,hFile,GetFileSize(hFile,NULL),PRE_SEND_SIZE,reinterpret_cast<LPOVERLAPPED>(pIoData),NULL,TF_USE_SYSTEM_THREAD);
            bRet
            =WSAGetLastError()==WSA_IO_PENDING;
            }

            else
            cout
            <<”Transmit File “<<”Error:”<<GetLastError()<<endl;

            return bRet;
            }


            DWORD WINAPI ThreadProc(LPVOID IocpHandle)
            {
            DWORD dwRecv
            =0;
            DWORD dwFlags
            =0;

            HANDLE hIocp
            =reinterpret_cast<HANDLE>(IocpHandle);
            DWORD dwTransCount
            =0;
            PPRE_IO_DATA pPreIoData
            =NULL;
            PPRE_SOCKET_DATA pPreHandleData
            =NULL;

            while(TRUE)
            {
            if(GetQueuedCompletionStatus(hIocp,&dwTransCount,
            reinterpret_cast
            <LPDWORD>(&pPreHandleData),
            reinterpret_cast
            <LPOVERLAPPED*>(&pPreIoData),INFINITE))
            {
            if(0==dwTransCount&&IoQuit!=pPreIoData->IoType)
            {
            cout
            <<”Client:”
            <<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
            <<”:”<<ntohs(pPreHandleData->ClientAddr.sin_port)
            <<” is closed”<<endl;

            closesocket(pPreHandleData
            ->hSocket);

            EnterCriticalSection(
            &csProtection);
            IoDataVector::iterator itrIoDelete
            =find(gIoDataVec.begin(),gIoDataVec.end(),pPreIoData);
            SocketDataVector::iterator itrSockDelete
            =find(gSockDataVec.begin(),gSockDataVec.end(),pPreHandleData);
            delete 
            *itrIoDelete;
            delete 
            *itrSockDelete;
            gIoDataVec.erase(itrIoDelete);
            gSockDataVec.erase(itrSockDelete);
            LeaveCriticalSection(
            &csProtection);

            continue;
            }


            switch(pPreIoData->IoType){
            case IoTransFile:
            cout
            <<”Client:”
            <<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
            <<”:”<<ntohs(pPreHandleData->ClientAddr.sin_port)
            <<” Transmit finished”<<endl;
            CloseHandle(
            *reinterpret_cast<HANDLE*>(pPreIoData->Buffer));
            goto LRERECV;

            case IoSend:
            cout
            <<”Client:”
            <<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
            <<”:”<<ntohs(pPreHandleData->ClientAddr.sin_port)
            <<” Send finished”<<endl;

            LRERECV:
            pPreIoData
            ->IoType=IoRecv;
            pPreIoData
            ->DataBuf.len=MAX_BUFFER_SIZE;
            memset(
            &pPreIoData->oa,0,sizeof(OVERLAPPED));

            WSARecv(pPreHandleData
            ->hSocket,&pPreIoData->DataBuf,1,
            &dwRecv,&dwFlags,
            reinterpret_cast
            <LPWSAOVERLAPPED>(pPreIoData),NULL);

            break;

            case IoRecv:
            cout
            <<”Client:”
            <<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
            <<”:”<<ntohs(pPreHandleData->ClientAddr.sin_port)
            <<” recv finished”<<endl;
            pPreIoData
            ->IoType=IoSend;

            if(!TransFile(pPreIoData,pPreHandleData,dwTransCount))
            {
            memset(
            &pPreIoData->oa,0,sizeof(OVERLAPPED));
            strcpy(pPreIoData
            ->DataBuf.buf,”File transmit error!\r\n”);
            pPreIoData
            ->DataBuf.len=strlen(pPreIoData->DataBuf.buf);

            WSASend(pPreHandleData
            ->hSocket,&pPreIoData->DataBuf,1,
            &dwRecv,dwFlags,
            reinterpret_cast
            <LPWSAOVERLAPPED>(pPreIoData),NULL);
            }

            break;

            case IoQuit:
            goto LQUIT;

            default:
            ;
            }

            }

            }


            LQUIT:
            return 0;
            }


            HANDLE hIocp
            =NULL;
            SOCKET hListen
            =NULL;

            BOOL WINAPI ShutdownHandler(DWORD dwCtrlType)
            {
            PRE_SOCKET_DATA PreSockData
            ={0};
            PRE_IO_DATA PreIoData
            ={0};

            PreIoData.IoType
            =IoQuit;

            if(hIocp)
            {
            PostQueuedCompletionStatus(hIocp,
            1,
            reinterpret_cast
            <ULONG_PTR>(&PreSockData),
            reinterpret_cast
            <LPOVERLAPPED>(&PreIoData));

            cout
            <<”Shutdown at “<<TimeNow()<<endl<<”wait for a moment please”<<endl;

            //讓出CPU時(shí)間,讓線程退出
            for(int t=0;t<80;t+=1)
            {
            Sleep(PRE_DOT_TIMER);
            cout
            <<”.”;
            }


            CloseHandle(hIocp);
            }


            int i=0;

            for(;i<gSockDataVec.size();i++)
            {
            PPRE_SOCKET_DATA pSockData
            =gSockDataVec[i];
            closesocket(pSockData
            ->hSocket);
            delete pSockData;
            }


            for(i=0;i<gIoDataVec.size();i++)
            {
            PPRE_IO_DATA pIoData
            =gIoDataVec[i];
            delete pIoData;
            }


            DeleteCriticalSection(
            &csProtection);
            if(hListen)
            closesocket(hListen);

            WSACleanup();
            exit(
            0);
            return TRUE;
            }


            LONG WINAPI MyExceptionFilter(
            struct _EXCEPTION_POINTERS *ExceptionInfo)
            {
            ShutdownHandler(
            0);
            return EXCEPTION_EXECUTE_HANDLER;
            }


            u_short DefPort
            =8182;

            int main(int argc,char **argv)
            {
            if(argc==2)
            DefPort
            =atoi(argv[1]);

            InitializeCriticalSection(
            &csProtection);
            SetUnhandledExceptionFilter(MyExceptionFilter);
            SetConsoleCtrlHandler(ShutdownHandler,TRUE);

            hIocp
            =CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);

            WSADATA data
            ={0};
            WSAStartup(
            0×0202,&data);

            hListen
            =socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
            if(INVALID_SOCKET==hListen)
            {
            ShutdownHandler(
            0);
            }


            SOCKADDR_IN addr
            ={0};
            addr.sin_family
            =AF_INET;
            addr.sin_port
            =htons(DefPort);

            if(bind(hListen,reinterpret_cast<PSOCKADDR>(&addr),
            sizeof(addr))==SOCKET_ERROR)
            {
            ShutdownHandler(
            0);
            }


            if(listen(hListen,256)==SOCKET_ERROR)
            ShutdownHandler(
            0);

            SYSTEM_INFO si
            ={0};
            GetSystemInfo(
            &si);
            si.dwNumberOfProcessors
            <<=1;

            for(int i=0;i<si.dwNumberOfProcessors;i++)
            {

            QueueUserWorkItem(ThreadProc,hIocp,WT_EXECUTELONGFUNCTION);
            }


            cout
            <<”Startup at “<<TimeNow()<<endl
            <<”work on port “<<DefPort<<endl
            <<”press CTRL+C to shutdown”<<endl<<endl<<endl;

            while(TRUE)
            {
            int namelen=sizeof(addr);
            memset(
            &addr,0,sizeof(addr));
            SOCKET hAccept
            =accept(hListen,reinterpret_cast<PSOCKADDR>(&addr),&namelen);

            if(hAccept!=INVALID_SOCKET)
            {
            cout
            <<”accept a client:”<<inet_ntoa(addr.sin_addr)<<”:”<<ntohs(addr.sin_port)<<endl;

            PPRE_SOCKET_DATA pPreHandleData
            =new PRE_SOCKET_DATA;
            pPreHandleData
            ->hSocket=hAccept;
            memcpy(
            &pPreHandleData->ClientAddr,&addr,sizeof(addr));

            CreateIoCompletionPort(reinterpret_cast
            <HANDLE>(hAccept),hIocp,reinterpret_cast<DWORD>(pPreHandleData),0);

            PPRE_IO_DATA pPreIoData
            =new(nothrow) PRE_IO_DATA;

            if(pPreIoData)
            {
            EnterCriticalSection(
            &csProtection);
            gSockDataVec.push_back(pPreHandleData);
            gIoDataVec.push_back(pPreIoData);
            LeaveCriticalSection(
            &csProtection);

            memset(pPreIoData,
            0,sizeof(PRE_IO_DATA));
            pPreIoData
            ->IoType=IoRecv;
            pPreIoData
            ->DataBuf.len=MAX_BUFFER_SIZE;
            pPreIoData
            ->DataBuf.buf=pPreIoData->Buffer;
            DWORD dwRecv
            =0;
            DWORD dwFlags
            =0;
            WSARecv(hAccept,
            &pPreIoData->DataBuf,1,&dwRecv,&dwFlags,reinterpret_cast<WSAOVERLAPPED*>(pPreIoData),NULL);
            }

            else
            {
            delete pPreHandleData;
            closesocket(hAccept);
            }

            }

            }


            return 0;
            }

            posted on 2008-01-07 16:47 isabc 閱讀(5472) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 串口通信

            廣告信息(免費(fèi)廣告聯(lián)系)

            中文版MSDN:
            歡迎體驗(yàn)

            久久九九免费高清视频| 久久综合综合久久97色| 亚洲精品无码成人片久久| 97精品伊人久久久大香线蕉| 久久婷婷成人综合色综合| 久久精品视频网| 久久久精品波多野结衣| 久久99久国产麻精品66| 77777亚洲午夜久久多喷| 国产成人综合久久精品尤物| 亚洲精品无码久久毛片| 久久久久久夜精品精品免费啦| 久久久久国产精品| 欧美精品乱码99久久蜜桃| 精品久久久久久无码专区不卡| 久久国产精品一区| 久久综合精品国产二区无码| 国产高潮国产高潮久久久91 | 久久精品?ⅴ无码中文字幕| 伊人久久大香线蕉无码麻豆| 国产精品久久久久久搜索| 亚洲国产天堂久久久久久| 精品一区二区久久久久久久网站| 久久亚洲精品无码播放| 国产精品美女久久久久久2018| 久久亚洲AV无码西西人体| 69久久精品无码一区二区| 国产精品久久久久久五月尺| 91久久成人免费| 久久精品国产亚洲AV无码偷窥| 亚洲精品国精品久久99热| 日本精品久久久久中文字幕8 | 久久亚洲精品无码AV红樱桃| 久久久久国产精品麻豆AR影院| 国内精品伊人久久久久AV影院| 久久精品综合网| 久久精品18| 久久精品成人免费观看97| 久久精品国产免费| 国产精品久久久久久搜索| 久久天堂AV综合合色蜜桃网 |