青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 298  文章 - 377  trackbacks - 0
<2013年2月>
272829303112
3456789
10111213141516
17181920212223
242526272812
3456789

常用鏈接

留言簿(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 聶文龍 閱讀(14576) 評論(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
@路過的
主線程主要處理連接,沒有連接時線程掛起,收、發在工作線程,這怎么不是異步  回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
              亚洲视频欧美在线| 欧美一区影院| 国产日韩欧美一区二区三区四区| 欧美日本成人| 国产精品久久久久久久电影| 国产精品久久久久久久一区探花| 国产精品高潮呻吟视频| 国产女主播一区| 黑人巨大精品欧美一区二区小视频 | 欧美日一区二区在线观看| 欧美四级剧情无删版影片| 国产精品手机在线| 1769国内精品视频在线播放| 亚洲精品国偷自产在线99热| 亚洲天堂免费观看| 欧美一区精品| 亚洲电影在线| 一区二区欧美亚洲| 久久九九99视频| 欧美理论大片| 国产一区二区久久| 日韩一区二区高清| 麻豆久久婷婷| 亚洲一级在线观看| 欧美激情视频在线免费观看 欧美视频免费一 | 免费一级欧美片在线播放| 亚洲欧洲另类国产综合| 亚洲影院色无极综合| 久久久亚洲午夜电影| 欧美日韩一区二区三区在线视频| 国产一区二区高清视频| 夜夜嗨av一区二区三区网页| 欧美午夜精品| 午夜精品在线| 欧美成人精精品一区二区频| 国产欧美一区二区精品性| 日韩视频在线观看国产| 欧美一区视频| 亚洲午夜精品国产| 欧美激情a∨在线视频播放| 国产亚洲激情在线| 亚洲在线播放电影| 亚洲国产福利在线| 久久视频在线免费观看| 国产伦精品一区二区三区视频孕妇 | 久久久久久久性| 亚洲小视频在线观看| 欧美精品在线免费| 亚洲人成网站影音先锋播放| 久久综合婷婷| 久久av红桃一区二区小说| 国产精品日韩一区| 性感少妇一区| 亚洲欧美资源在线| 国产精品揄拍一区二区| 午夜精品视频网站| 一区二区三区黄色| 欧美日韩亚洲一区二区| 亚洲午夜小视频| 一区二区三区久久网| 欧美日韩在线不卡一区| 亚洲性线免费观看视频成熟| 99精品99久久久久久宅男| 欧美日韩一区二区三区在线| 亚洲一本视频| 亚洲综合社区| 狠狠干狠狠久久| 欧美成人一区在线| 欧美黄色小视频| 中文国产亚洲喷潮| 亚洲免费在线观看| 很黄很黄激情成人| 亚洲高清视频一区| 欧美日韩一区在线观看| 欧美伊人久久久久久久久影院| 亚洲欧美精品在线观看| 国内视频一区| 最新国产成人在线观看| 欧美性猛交视频| 久久久精彩视频| 欧美成人在线免费视频| 亚洲天堂av高清| 先锋影音国产一区| 最新日韩欧美| 亚洲午夜未删减在线观看| 国产一区二区欧美| 欧美日韩岛国| 亚洲黄色影片| 在线一区二区三区四区五区| 国产精品久久久久天堂| 久久免费视频在线观看| 欧美电影美腿模特1979在线看| 一区二区精品在线| 翔田千里一区二区| 日韩视频专区| 久久av最新网址| 亚洲视频精品| 免费成人av| 欧美一区亚洲| 欧美日韩精品免费| 久久亚洲春色中文字幕久久久| 欧美成人一区二区三区在线观看| 亚洲欧美久久久| 另类酷文…触手系列精品集v1小说| 日韩午夜中文字幕| 久久精品论坛| 欧美一级在线视频| 欧美成人三级在线| 久久精品一本久久99精品| 欧美激情一区二区三区四区| 久久精品免费观看| 国产精品第十页| 亚洲第一黄色网| 国产自产在线视频一区| 99亚洲一区二区| 亚洲精品在线观看视频| 久久久精品国产一区二区三区| 亚洲影音先锋| 欧美日韩视频一区二区三区| 亚洲国产成人av| 136国产福利精品导航网址| 校园激情久久| 午夜精品成人在线| 欧美日韩在线影院| 亚洲老司机av| 9l国产精品久久久久麻豆| 久热re这里精品视频在线6| 久久久久久9999| 国产一区二区丝袜高跟鞋图片 | 亚洲精品中文字幕在线| 在线日本欧美| 久久精品女人的天堂av| 久久久久久亚洲综合影院红桃 | 欧美成人第一页| 欧美xxx成人| 亚洲国产专区| 欧美激情bt| 99精品欧美| 亚洲欧美日韩国产| 国产精品美女久久久免费| 一区二区冒白浆视频| 中文无字幕一区二区三区| 欧美日韩国产专区| 一本色道久久综合狠狠躁的推荐| 99av国产精品欲麻豆| 欧美日韩精品| 亚洲资源av| 久久久噜噜噜久久人人看| 在线观看视频欧美| 在线观看一区二区精品视频| 亚洲欧美视频在线观看视频| 亚洲欧美在线磁力| 国产欧美va欧美不卡在线| 欧美一级片一区| 免费不卡中文字幕视频| 亚洲人体1000| 欧美亚洲成人免费| 午夜久久电影网| 欧美成在线观看| 亚洲一区二区在线免费观看视频| 国产精品久久久久久一区二区三区| 亚洲私人影院| 看片网站欧美日韩| 一区二区三欧美| 国产欧美二区| 榴莲视频成人在线观看| 亚洲剧情一区二区| 久久成人精品| 日韩一区二区电影网| 国产女人精品视频| 鲁大师成人一区二区三区| 亚洲理论在线观看| 久久一区视频| 亚洲一区二区免费| 在线精品观看| 国产精品日本精品| 欧美高清视频在线| 香港久久久电影| 亚洲电影av| 久久精品一本久久99精品| 99综合在线| 亚洲电影免费| 国产麻豆综合| 欧美日韩精品免费观看| 久久久国产精品一区二区中文| 亚洲最新中文字幕| 国产精品视频免费一区| 国产欧美日韩精品一区| 久久亚洲一区二区| 亚洲精品一区在线观看香蕉| 欧美在线观看视频在线| 亚洲精品一区二区三区四区高清| 国产精品毛片a∨一区二区三区|国| 久久精品一区| 亚洲一区二区三区免费观看| 欧美黄色大片网站| 久久久另类综合| 欧美一区二区在线免费观看| 在线视频一区二区| 亚洲国产国产亚洲一二三|