• <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
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            常用鏈接

            留言簿(34)

            隨筆分類

            隨筆檔案

            文章檔案

            相冊

            收藏夾

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

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

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

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

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

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

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

            這個例子比較簡單,沒有復雜的數據處理過程(正在設計中,和大家交流交流)。用的是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<<"連接服務器..."<<endl;
                if(connect(sockClient,(const struct sockaddr *)&addrServer,sizeof(sockaddr)) != 0)
                {
                    cout<<"connect 失敗"<<endl;
                    WSACleanup();
                    goto theend;
                }
                cout<<"開始發送測試包"<<endl;
                memset(buf,0,24);
                while(true)
                {
                    sprintf(buf,"第%d個包", n);
                    cout<<"發送:"<<buf<<endl;
                    if(send(sockClient,buf,strlen(buf),0) <= 0)
                    {
                        cout<<"send失敗,可能連接斷開"<<endl;
                        //break;
                        goto theend;
                    }
                    memset(buf,0,24);

                    //接收服務端應答
                    if(recv(sockClient,buf,24,0) <= 0)
                    {
                        cout<<"recv失敗,可能連接斷開"<<endl;
                       //break;
                       goto theend;
                    }
                    cout<<"服務器應答:"<<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;
            }

            服務端。

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

            #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<<"初始環境..."<<endl;
                if(Init() != 0)
                    goto theend;

                //創建一個IO完成端口
                cout<<"創建一個IO完成端口"<<endl;
                hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
                if(hCompletionPort == INVALID_HANDLE_VALUE)
                {
                    cout<<"創建IO完成端口失敗"<<endl;
                    goto theend;
                }
                //獲取CPU數目
                GetSystemInfo(&siSys);
                //創建一定數目的工作者線程,本例中以一個處理器一個線程搭配
                for(int i = 0;i<(int)siSys.dwNumberOfProcessors*2;i++)//NumberOfProcessors
                {
                    HANDLE hThread;
                    hThread = CreateThread(NULL,0,ServerWorkerThread,(LPVOID)hCompletionPort,0,&nThreadID);
                    cout<<"創建工作者線程"<<i<<endl;
                    CloseHandle(hThread);
                }
                //創建監聽SOCKET
                cout<<"創建監聽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;
                }
                //準備監聽
                cout<<"準備監聽"<<endl;
                if(listen(sockListen,5)!=0)
                {
                    cout<<"listen錯誤"<<endl;
                    goto theend;
                }
                while(true)
                {
                    //接收用戶連接,被和完成端口關聯
                    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;
                    }
                    //關聯
                    cout<<"關聯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);

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

                    //為請求服務
                   
                    if(PerIoData->OperationType == RECV_POSTED)
                    {
                        //處理
                        cout<<"接收處理"<<endl;
                        cout<<PerHandleData->sock<<"SOCKET :"<<PerIoData->Buff<<endl;
                        //回應客戶端
                        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)
                    {
                        //發送時的處理
                        cout<<"發送處理"<<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,還是同步 我就是想知道你是怎么投遞的

            是不是一調用中廣核WSARecv就馬上能夠返回的嗎?

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


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



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

            如果你調用WSARecv函數投遞,如果這個函數一直堵塞在這里,那談何效率


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


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

            就是說:

            如何在IOCP中,使用異步IO


              回復  更多評論
              
            # re: IOCP的例子 [未登錄] 2013-02-28 19:41 Fairy
            在我的機子上 怎么不行 wsarecv總是返回10045   回復  更多評論
              
            # re: IOCP的例子  2013-06-04 14:54 tankin
            @Fairy
            Flag 要修改成 0
            因為是一個[in][out] 值  回復  更多評論
              
            # re: IOCP的例子  2013-11-11 17:12 good90
            WSARecv中dwFlags lz都不初始。。  回復  更多評論
              
            # re: IOCP的例子  2013-11-22 12:38 路過的
            這代碼 簡直是誤導人 在WSAAccept 這里就開始一直在阻塞主線程了 你還怎么異步  回復  更多評論
              
            # re: IOCP的例子  2014-11-30 16:16 apc
            @路過的
            主線程主要處理連接,沒有連接時線程掛起,收、發在工作線程,這怎么不是異步  回復  更多評論
              
            国产日韩久久久精品影院首页| 久久亚洲精品成人无码网站| 国产精品丝袜久久久久久不卡| 日本免费久久久久久久网站| 亚洲?V乱码久久精品蜜桃| 亚洲国产精品无码久久一区二区| 99国产精品久久| 婷婷久久综合九色综合绿巨人| 97久久国产综合精品女不卡 | 婷婷综合久久中文字幕蜜桃三电影| 久久精品一本到99热免费| 久久精品国产精品国产精品污 | 性欧美大战久久久久久久久| 久久免费小视频| 伊人久久大香线蕉综合影院首页| 精品乱码久久久久久夜夜嗨| 久久久无码一区二区三区| 精品国产日韩久久亚洲| 国内精品久久久久久麻豆| 97久久超碰国产精品旧版| 国产精品久久久久久久久软件| 精品久久久久久99人妻| 99久久成人国产精品免费| 无码人妻少妇久久中文字幕蜜桃 | 精品久久久久久国产免费了| 亚洲综合熟女久久久30p| 色综合久久88色综合天天 | 丁香五月综合久久激情| 久久成人精品视频| 色综合久久中文综合网| 久久综合丁香激情久久| 国产精品久久国产精品99盘| 久久久久人妻一区精品色| 久久亚洲AV成人出白浆无码国产| 国产精品久久久香蕉| 久久无码国产专区精品| 欧美日韩精品久久久久| 久久夜色精品国产噜噜亚洲AV| 伊人久久大香线蕉av不卡| 国产午夜免费高清久久影院| 久久91精品国产91久久户|