• <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>
            隨筆 - 298  文章 - 377  trackbacks - 0
            <2007年8月>
            2930311234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678

            常用鏈接

            留言簿(34)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            收藏夾

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            以前在書上看過了IOCP,不過一直都沒有寫過代碼。現(xiàn)在寫的時候,著時對很多問題摸不著頭腦。不過好在CSDN上有許多的對于IOCP問題的討論帖,讓我受益非淺啊,也把心中的一些迷茫解開了,下面給出的是可以運行的IOCP的C/S代碼,自已試了在一個機(jī)器上開了一百來個客戶端,跑起來暫時沒出現(xiàn)問題(因為通信內(nèi)容太簡單了^-^)。

            IOCP的三個函數(shù):CreateIoCompletionPort、GetQueuedCompletionStatus、PostQueuedCompletionStatus;一個是用來創(chuàng)建想要的IOCP的HANDLE同時也是用來把我們想要的SOCKET綁定到這個HANDLE上,一個是獲取IO這個HANDLE上對應(yīng)的對列的狀態(tài),看有沒有事件完成,一個是用來通知所有工作線程退出(這個函數(shù)我還沒用到,關(guān)于這個功用是看資料上說的)。

            我在寫這個代碼的時候,最主要的問題就是當(dāng)通信完成了之后,是怎么樣來判斷是哪個SOCKET的哪個狀態(tài)(SEND還是RECV)完成了。《WINDOWS網(wǎng)絡(luò)編程》這本書里給的代碼不是很全的哦,它的配套光盤又沒有,不過好在CSDN里CB那塊中有個朋友剛好帖出了這一章的代碼。通過比較和一夜的思量,算是搞明白啦。主要的就是以下的數(shù)據(jù):

            1、在第二次CreateIoCompletionPort中,會傳進(jìn)去一個CompletionKey,這個就是要來關(guān)聯(lián)到我們想要的SOCKET上的一些感興趣的數(shù)據(jù)內(nèi)容,當(dāng)然最好是要一個SOCKET,也可以是其它,看自己程序的需要了。而通過GetQueueCompletionStatus的通過,就可以獲得這些數(shù)據(jù)的地址了。

            typedef struct _PER_HANDLE_DATA
            {
                SOCKET sock;
            }PER_HANDLE_DATA,* LPPER_HANDLE_DATA;

            2、第二個主要的數(shù)據(jù)結(jié)構(gòu)就是這個了,現(xiàn)在真的是佩服當(dāng)初設(shè)計這個結(jié)構(gòu)的人啊(沒辦法,自己就是沒想到這樣利用法)。因為在POST操作(SEND或是RECV)是,都要一個OVERLAPPED,所以就把這個OVERLAPPED和要指明這次POST操作類型的代碼OperationType(POST_SEND或POST_RECV)以及其它一些數(shù)據(jù)(比如接發(fā)收的緩沖)。這樣子,在GetQueueCompletionStatus的時候,通過獲取事件,也同時得到了OperationType和緩沖。這樣,知道了通信類型,也得到了緩沖數(shù)據(jù)的緩沖區(qū)。這樣就可以控制我們的通信了。

            這個例子比較簡單,沒有復(fù)雜的數(shù)據(jù)處理過程(正在設(shè)計中,和大家交流交流)。用的是BCB的平臺,不過寫法上還是和VC里的一模一樣的啊。

            typedef struct _PER_IO_OPERATION_DATA
            {
                OVERLAPPED Overlapped;
                WSABUF DataBuff[1];
                char Buff[24];
                BOOL OperationType;
            }PER_IO_OPERATION_DATA,* LPPER_IO_OPERATION_DATA;

            簡單的客戶端:

            //---------------------------------------------------------------------------

            #pragma hdrstop
            #include <winsock2.h>
            #include <stdio.h>
            #include <iostream>
            using namespace std;
            //---------------------------------------------------------------------------

            #pragma argsused

            SOCKET sockClient;
            struct sockaddr_in addrServer;
            char buf[24];
            int n = 0;
            int Init();

            int main(int argc, char* argv[])
            {
                if(Init() != 0)
                    goto theend;

                sockClient = socket(AF_INET,SOCK_STREAM,0);
                if(sockClient == INVALID_SOCKET)
                {
                    cout<<"socket 失敗"<<endl;
                    WSACleanup();
                    goto theend;
                }
                memset(&addrServer,0,sizeof(sockaddr_in));
                addrServer.sin_family = AF_INET;
                addrServer.sin_addr.s_addr = inet_addr("127.0.0.1");
                addrServer.sin_port = htons(9090);
                cout<<"連接服務(wù)器..."<<endl;
                if(connect(sockClient,(const struct sockaddr *)&addrServer,sizeof(sockaddr)) != 0)
                {
                    cout<<"connect 失敗"<<endl;
                    WSACleanup();
                    goto theend;
                }
                cout<<"開始發(fā)送測試包"<<endl;
                memset(buf,0,24);
                while(true)
                {
                    sprintf(buf,"第%d個包", n);
                    cout<<"發(fā)送:"<<buf<<endl;
                    if(send(sockClient,buf,strlen(buf),0) <= 0)
                    {
                        cout<<"send失敗,可能連接斷開"<<endl;
                        //break;
                        goto theend;
                    }
                    memset(buf,0,24);

                    //接收服務(wù)端應(yīng)答
                    if(recv(sockClient,buf,24,0) <= 0)
                    {
                        cout<<"recv失敗,可能連接斷開"<<endl;
                       //break;
                       goto theend;
                    }
                    cout<<"服務(wù)器應(yīng)答:"<<buf<<endl;
                    memset(buf,0,24);

                    Sleep(200);
                    n++;
                }

               
            theend:
                WSACleanup();
                getchar();
                return 0;
            }
            //---------------------------------------------------------------------------
            int Init()
            {
                WSAData wsaData;
                if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
                {
                    cout<<"WSAStartup失敗"<<endl;
                    return -1;
                }

                if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
                {
                    cout<<"SOCKET版本不對"<<endl;
                    WSACleanup();
                    return -1;
                }
                return 0;
            }

            服務(wù)端。

            //---------------------------------------------------------------------------

            #pragma hdrstop

            //---------------------------------------------------------------------------
            #pragma argsused
            #pragma comment(lib,"ws2_32.lib")
            #include <stdio.h>
            #include <memory.h>
            #include <winsock2.h>
            #include <iostream>
            using namespace std;

            #define RECV_POSTED 1001
            #define SEND_POSTED 1002

            int Init();

            HANDLE hCompletionPort;
            typedef struct _PER_HANDLE_DATA
            {
                SOCKET sock;
            }PER_HANDLE_DATA,* LPPER_HANDLE_DATA;

            typedef struct _PER_IO_OPERATION_DATA
            {
                OVERLAPPED Overlapped;
                WSABUF DataBuff[1];
                char Buff[24];
                BOOL OperationType;
            }PER_IO_OPERATION_DATA,* LPPER_IO_OPERATION_DATA;

            DWORD WINAPI ServerWorkerThread(LPVOID CompletionPort);

            int main(int argc, char* argv[])
            {
                LPPER_HANDLE_DATA perHandleData;
                LPPER_IO_OPERATION_DATA ioperdata;
                SYSTEM_INFO siSys;
                SOCKET sockListen;
                struct sockaddr_in addrLocal;
                char buf[24];
                int nRet = 0;
                DWORD nThreadID;
                SOCKET sockAccept;
                DWORD dwFlags;
                DWORD dwRecvBytes;
                int nReuseAddr = 1;

                cout<<"初始環(huán)境..."<<endl;
                if(Init() != 0)
                    goto theend;

                //創(chuàng)建一個IO完成端口
                cout<<"創(chuàng)建一個IO完成端口"<<endl;
                hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
                if(hCompletionPort == INVALID_HANDLE_VALUE)
                {
                    cout<<"創(chuàng)建IO完成端口失敗"<<endl;
                    goto theend;
                }
                //獲取CPU數(shù)目
                GetSystemInfo(&siSys);
                //創(chuàng)建一定數(shù)目的工作者線程,本例中以一個處理器一個線程搭配
                for(int i = 0;i<(int)siSys.dwNumberOfProcessors*2;i++)//NumberOfProcessors
                {
                    HANDLE hThread;
                    hThread = CreateThread(NULL,0,ServerWorkerThread,(LPVOID)hCompletionPort,0,&nThreadID);
                    cout<<"創(chuàng)建工作者線程"<<i<<endl;
                    CloseHandle(hThread);
                }
                //創(chuàng)建監(jiān)聽SOCKET
                cout<<"創(chuàng)建監(jiān)聽SOCKET"<<endl;
                sockListen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
                if(sockListen == SOCKET_ERROR)
                {
                    cout<<"WSASocket錯誤"<<endl;
                    goto theend;
                }

                if(setsockopt(sockListen,SOL_SOCKET,SO_REUSEADDR,(const char *)&nReuseAddr,sizeof(int)) != 0)
                {
                    cout<<"setsockopt錯誤"<<endl;
                    goto theend;
                }
                addrLocal.sin_family = AF_INET;
                addrLocal.sin_addr.s_addr = htonl(INADDR_ANY);
                addrLocal.sin_port = htons(9090);
                if(bind(sockListen,(struct sockaddr *)&addrLocal,sizeof(sockaddr_in)) != 0)
                {
                    cout<<"bind錯誤"<<endl;
                    int n = WSAGetLastError();
                    goto theend;
                }
                //準(zhǔn)備監(jiān)聽
                cout<<"準(zhǔn)備監(jiān)聽"<<endl;
                if(listen(sockListen,5)!=0)
                {
                    cout<<"listen錯誤"<<endl;
                    goto theend;
                }
                while(true)
                {
                    //接收用戶連接,被和完成端口關(guān)聯(lián)
                    sockAccept = WSAAccept(sockListen,NULL,NULL,NULL,0);
                    perHandleData = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
                    if(perHandleData == NULL)
                        continue;
                    cout<<"socket number "<<sockAccept<<"接入"<<endl;
                    perHandleData->sock = sockAccept;

                    ioperdata = (LPPER_IO_OPERATION_DATA)malloc(sizeof(PER_IO_OPERATION_DATA));
                    memset(&(ioperdata->Overlapped),0,sizeof(OVERLAPPED));
                    (ioperdata->DataBuff[0]).len = 24;
                    (ioperdata->DataBuff[0]).buf = ioperdata->Buff;
                    ioperdata->OperationType = RECV_POSTED;
                    if( ioperdata == NULL)
                    {
                        free(perHandleData);
                        continue;
                    }
                    //關(guān)聯(lián)
                    cout<<"關(guān)聯(lián)SOCKET和完成端口"<<endl;
                    if(CreateIoCompletionPort((HANDLE)sockAccept,hCompletionPort,(DWORD)perHandleData,1) == NULL)
                    {
                        cout<<sockAccept<<"createiocompletionport錯誤"<<endl;
                        free(perHandleData);
                        free(ioperdata);
                        continue;
                    }
                    //投遞接收操作
                    cout<<"投遞接收操作"<<endl;
                    WSARecv(perHandleData->sock,ioperdata->DataBuff,1,&dwRecvBytes,&dwFlags,&(ioperdata->Overlapped),NULL);
                }
            theend:
                getchar();
                return 0;
            }
            //---------------------------------------------------------------------------
            int Init()
            {
                WSAData wsaData;
                if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
                {
                    cout<<"WSAStartup失敗"<<endl;
                    return -1;
                }

                if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
                {
                    cout<<"SOCKET版本不對"<<endl;
                    WSACleanup();
                    return -1;
                }
                return 0;
            }

            DWORD WINAPI ServerWorkerThread(LPVOID CompletionPort)
            {
                HANDLE ComPort = (HANDLE)CompletionPort;
                DWORD BytesTransferred;
                LPOVERLAPPED Overlapped;
                LPPER_HANDLE_DATA PerHandleData;
                LPPER_IO_OPERATION_DATA PerIoData;
                DWORD SendBytes,RecvBytes;
                DWORD Flags;
                BOOL bT;

                while(TRUE)
                {
                    //等待完成端口上SOCKET的完成
                    cout<<"等待完成端口上SOCKET的完成"<<endl;
                    bT = GetQueuedCompletionStatus(ComPort,
                        &BytesTransferred,(LPDWORD)&PerHandleData,
                        (LPOVERLAPPED *)&PerIoData,INFINITE);

                    //檢查是否有錯誤產(chǎn)生
                    if(BytesTransferred == 0 &&
                        (PerIoData->OperationType == RECV_POSTED ||
                        PerIoData->OperationType == SEND_POSTED))
                    {
                        //關(guān)閉SOCKET
                        cout<<PerHandleData->sock<<"SOCKET關(guān)閉"<<endl;
                        closesocket(PerHandleData->sock);
                        free(PerHandleData);
                        free(PerIoData);
                        continue;
                    }

                    //為請求服務(wù)
                   
                    if(PerIoData->OperationType == RECV_POSTED)
                    {
                        //處理
                        cout<<"接收處理"<<endl;
                        cout<<PerHandleData->sock<<"SOCKET :"<<PerIoData->Buff<<endl;
                        //回應(yīng)客戶端
                        ZeroMemory(PerIoData->Buff,24);
                        strcpy(PerIoData->Buff,"OK");
                        Flags = 0;
                        ZeroMemory((LPVOID)&(PerIoData->Overlapped),sizeof(OVERLAPPED));
                        PerIoData->DataBuff[0].len = 2;
                        PerIoData->DataBuff[0].buf = PerIoData->Buff;
                        PerIoData->OperationType = SEND_POSTED;
                        WSASend(PerHandleData->sock,PerIoData->DataBuff,
                            1,&SendBytes,0,&(PerIoData->Overlapped),NULL);
                    }
                    else //if(PerIoData->OperationType == SEND_POSTED)
                    {
                        //發(fā)送時的處理
                        cout<<"發(fā)送處理"<<endl;
                        Flags = 0;
                        ZeroMemory((LPVOID)&(PerIoData->Overlapped),sizeof(OVERLAPPED));
                        ZeroMemory(PerIoData->Buff,24);
                        PerIoData->DataBuff[0].len = 24;
                        PerIoData->DataBuff[0].buf = PerIoData->Buff;
                        PerIoData->OperationType = RECV_POSTED;
                        WSARecv(PerHandleData->sock,PerIoData->DataBuff,
                            1,&RecvBytes,&Flags,&(PerIoData->Overlapped),NULL);
                    }
                }
            }


            posted on 2007-08-17 11:55 聶文龍 閱讀(14533) 評論(7)  編輯 收藏 引用 所屬分類: net work

            FeedBack:
            # re: IOCP的例子  2010-07-04 16:03 adsads
            請教下:
            WSARecv(perHandleData->sock,ioperdata->DataBuff,1,&dwRecvBytes,&dwFlags,&(ioperdata->Overlapped),NULL);

            我碰到幾個問題:

            1、IO投遞,WSARecv,是異步IO,還是同步 我就是想知道你是怎么投遞的

            是不是一調(diào)用中廣核WSARecv就馬上能夠返回的嗎?

            2、關(guān)聯(lián)數(shù)據(jù)CreateIoCompletionPort()為什么 我在XP上寫的代碼 這個函數(shù) 在 在關(guān)聯(lián)數(shù)據(jù)的時候,總是失敗呢?錯誤是87 參數(shù)不正確,但我按照其他人寫的代碼,結(jié)果全是一樣


            如果你真的在實戰(zhàn)中使用過,我向你請教,希望你不吝賜教



              回復(fù)  更多評論
              
            # re: IOCP的例子  2010-07-04 16:05 adsads
            還是管IO投遞

            如果你調(diào)用WSARecv函數(shù)投遞,如果這個函數(shù)一直堵塞在這里,那談何效率


            如果你真的是做到異步IO的話,希望你能幫我下


            因為這個問題,困擾我很久了

            就是說:

            如何在IOCP中,使用異步IO


              回復(fù)  更多評論
              
            # re: IOCP的例子 [未登錄] 2013-02-28 19:41 Fairy
            在我的機(jī)子上 怎么不行 wsarecv總是返回10045   回復(fù)  更多評論
              
            # re: IOCP的例子  2013-06-04 14:54 tankin
            @Fairy
            Flag 要修改成 0
            因為是一個[in][out] 值  回復(fù)  更多評論
              
            # re: IOCP的例子  2013-11-11 17:12 good90
            WSARecv中dwFlags lz都不初始。。  回復(fù)  更多評論
              
            # re: IOCP的例子  2013-11-22 12:38 路過的
            這代碼 簡直是誤導(dǎo)人 在WSAAccept 這里就開始一直在阻塞主線程了 你還怎么異步  回復(fù)  更多評論
              
            # re: IOCP的例子  2014-11-30 16:16 apc
            @路過的
            主線程主要處理連接,沒有連接時線程掛起,收、發(fā)在工作線程,這怎么不是異步  回復(fù)  更多評論
              
            色综合久久综精品| 久久91精品国产91久久户| 久久99国产精品久久久| 久久婷婷色综合一区二区| 久久99精品九九九久久婷婷| 一本久久久久久久| 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲高清不卡 国产成人精品久久亚洲 | 性做久久久久久久久久久| 久久国产免费| 无码8090精品久久一区| 久久一区二区免费播放| 伊人色综合九久久天天蜜桃| 久久综合鬼色88久久精品综合自在自线噜噜| 欧美激情精品久久久久久| 久久久高清免费视频| 少妇高潮惨叫久久久久久| 2021久久国自产拍精品| 精品久久久久久无码人妻蜜桃| 久久免费国产精品| 亚洲乱码中文字幕久久孕妇黑人 | 久久无码专区国产精品发布| 国产偷久久久精品专区| 国产麻豆精品久久一二三| 国产69精品久久久久99| 亚洲精品99久久久久中文字幕| 综合久久国产九一剧情麻豆| 91久久婷婷国产综合精品青草| 精品乱码久久久久久夜夜嗨| 人人狠狠综合88综合久久| 人妻少妇久久中文字幕| 成人午夜精品久久久久久久小说| 久久久久这里只有精品 | 国产99久久久国产精免费| 婷婷久久五月天| 国产ww久久久久久久久久| 亚洲综合熟女久久久30p| 国内精品久久久久久久亚洲| av色综合久久天堂av色综合在| 日本免费一区二区久久人人澡| 精品久久人人爽天天玩人人妻| 99久久精品免费|