• <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)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊(cè)

            收藏夾

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

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

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

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

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

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

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

            這個(gè)例子比較簡單,沒有復(fù)雜的數(shù)據(jù)處理過程(正在設(shè)計(jì)中,和大家交流交流)。用的是BCB的平臺(tái),不過寫法上還是和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個(gè)包", 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版本不對(duì)"<<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)建一個(gè)IO完成端口
                cout<<"創(chuàng)建一個(gè)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ù)目的工作者線程,本例中以一個(gè)處理器一個(gè)線程搭配
                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錯(cuò)誤"<<endl;
                    goto theend;
                }

                if(setsockopt(sockListen,SOL_SOCKET,SO_REUSEADDR,(const char *)&nReuseAddr,sizeof(int)) != 0)
                {
                    cout<<"setsockopt錯(cuò)誤"<<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錯(cuò)誤"<<endl;
                    int n = WSAGetLastError();
                    goto theend;
                }
                //準(zhǔn)備監(jiān)聽
                cout<<"準(zhǔn)備監(jiān)聽"<<endl;
                if(listen(sockListen,5)!=0)
                {
                    cout<<"listen錯(cuò)誤"<<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錯(cuò)誤"<<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版本不對(duì)"<<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);

                    //檢查是否有錯(cuò)誤產(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;
                    }

                    //為請(qǐng)求服務(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ā)送時(shí)的處理
                        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 聶文龍 閱讀(14550) 評(píng)論(7)  編輯 收藏 引用 所屬分類: net work

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

            我碰到幾個(gè)問題:

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

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

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


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



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

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


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


            因?yàn)檫@個(gè)問題,困擾我很久了

            就是說:

            如何在IOCP中,使用異步IO


              回復(fù)  更多評(píng)論
              
            # re: IOCP的例子 [未登錄] 2013-02-28 19:41 Fairy
            在我的機(jī)子上 怎么不行 wsarecv總是返回10045   回復(fù)  更多評(píng)論
              
            # re: IOCP的例子  2013-06-04 14:54 tankin
            @Fairy
            Flag 要修改成 0
            因?yàn)槭且粋€(gè)[in][out] 值  回復(fù)  更多評(píng)論
              
            # re: IOCP的例子  2013-11-11 17:12 good90
            WSARecv中dwFlags lz都不初始。。  回復(fù)  更多評(píng)論
              
            # re: IOCP的例子  2013-11-22 12:38 路過的
            這代碼 簡直是誤導(dǎo)人 在WSAAccept 這里就開始一直在阻塞主線程了 你還怎么異步  回復(fù)  更多評(píng)論
              
            # re: IOCP的例子  2014-11-30 16:16 apc
            @路過的
            主線程主要處理連接,沒有連接時(shí)線程掛起,收、發(fā)在工作線程,這怎么不是異步  回復(fù)  更多評(píng)論
              
            欧美久久亚洲精品| 久久精品国产亚洲精品| 久久精品麻豆日日躁夜夜躁| 久久久久亚洲AV片无码下载蜜桃| 国产Av激情久久无码天堂| 国产激情久久久久影院小草| 久久久亚洲AV波多野结衣 | 亚洲一区中文字幕久久| 国产呻吟久久久久久久92| 久久午夜无码鲁丝片秋霞| 国产精品99久久精品| 中文字幕精品久久久久人妻| 久久九九亚洲精品| 丁香色欲久久久久久综合网| 久久国产精品波多野结衣AV | 日本久久久久亚洲中字幕| 中文字幕一区二区三区久久网站| 亚洲国产一成久久精品国产成人综合 | 国产午夜精品久久久久九九电影| 一本色道久久88—综合亚洲精品 | 久久精品无码一区二区日韩AV| 人妻无码αv中文字幕久久 | 亚洲欧美日韩中文久久| 国产69精品久久久久9999| 久久久一本精品99久久精品88| 久久夜色撩人精品国产| 国产精品青草久久久久福利99| 99久久成人国产精品免费| 99久久夜色精品国产网站| 亚洲精品久久久www| 久久久久久久久久久免费精品| 伊人色综合久久天天| 久久久久综合网久久| 国产91色综合久久免费| 99国产欧美久久久精品蜜芽| 亚洲国产精品久久电影欧美| 国内精品综合久久久40p| 亚洲中文字幕久久精品无码喷水| 中文精品久久久久人妻| 国产激情久久久久久熟女老人| 久久99国产精品久久99小说|