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

隨筆 - 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>
              欧美日韩精品在线| 永久免费视频成人| 欧美高清不卡| 亚洲午夜影视影院在线观看| 欧美性片在线观看| 欧美美女操人视频| 欧美国产国产综合| 欧美日韩三区四区| 日韩视频免费在线| 最近看过的日韩成人| 欧美在线一级va免费观看| 欧美一区二区黄| 欧美a级理论片| 亚洲国产精品va在线观看黑人| 久久成人国产| 亚洲激情av| 午夜久久久久久| 久久久亚洲欧洲日产国码αv| 久久久久久亚洲综合影院红桃 | 亚洲国产高清自拍| 国产日韩欧美在线视频观看| 国产亚洲欧美一区二区| 亚洲大胆av| 亚洲欧美在线视频观看| 欧美黄色成人网| 亚洲综合色在线| 欧美日韩国产精品一区| 亚洲福利视频网站| 久久精品国产v日韩v亚洲| 最近中文字幕mv在线一区二区三区四区| 正在播放欧美视频| 欧美日韩国产999| 亚洲人成小说网站色在线| 久久精品亚洲一区二区三区浴池| 亚洲激情偷拍| 欧美国产视频在线观看| 尤物九九久久国产精品的分类| 亚洲欧美日韩第一区| 欧美福利视频在线| 99视频精品| 国产精品黄色在线观看| 9色porny自拍视频一区二区| 欧美激情亚洲另类| 欧美激情久久久| 亚洲视频在线观看免费| 亚洲无线视频| 国产一区二区在线观看免费播放 | 美日韩精品视频免费看| 亚洲高清一区二| 亚洲三级性片| 欧美新色视频| 你懂的亚洲视频| 欧美日韩视频免费播放| 亚洲欧美日韩精品久久久| 中文av字幕一区| 狠狠色丁香婷婷综合影院| 美女视频网站黄色亚洲| 欧美视频免费| 免费观看亚洲视频大全| 欧美日韩在线不卡| 欧美88av| 国产精品一区免费观看| 欧美另类视频| 日韩亚洲一区二区| 欧美人与禽猛交乱配视频| 久久久久久9| 亚洲精品国产精品乱码不99 | 久久久久久9| 欧美黄色网络| 亚洲毛片一区二区| 亚洲图片欧美午夜| 欧美一区二区三区免费视| 国内精品免费在线观看| 日韩视频二区| 欧美久久久久免费| 亚洲精品在线观看免费| 久久精品国产欧美激情| 欧美色视频日本高清在线观看| 亚洲激情视频网| 久久精品九九| 久久久久综合一区二区三区| 国产精品美女久久久久久2018| 亚洲人妖在线| 日韩亚洲欧美中文三级| 欧美日韩成人在线观看| 亚洲欧洲精品一区二区精品久久久| 欧美日韩日日夜夜| 欧美成人一区二区三区| 欧美视频在线观看视频极品| 一区二区国产日产| 欧美在线三级| 激情欧美亚洲| 欧美激情一区| 亚洲欧美视频一区| 亚洲国产欧美日韩| 欧美伊人久久久久久久久影院| 国产深夜精品| 欧美啪啪成人vr| 欧美一区二区三区在线播放| 欧美不卡视频| 欧美一区日韩一区| 99国产精品久久久久久久久久 | 欧美成年视频| 99在线精品观看| 亚洲毛片在线看| 国产视频一区在线| 欧美色欧美亚洲另类二区| 久久亚洲捆绑美女| 久久成人av少妇免费| 一区二区三区久久久| 欧美高清在线视频观看不卡| 欧美一级精品大片| 亚洲欧美在线aaa| 亚洲专区在线视频| 一区二区精品在线| 99re国产精品| 这里是久久伊人| 亚洲免费伊人电影在线观看av| 91久久线看在观草草青青| 亚洲国产小视频| 亚洲乱码久久| 亚洲天堂成人在线观看| 亚洲午夜女主播在线直播| 亚洲小说欧美另类社区| 午夜老司机精品| 美女视频网站黄色亚洲| 亚洲国产成人精品女人久久久 | 一本色道久久88综合亚洲精品ⅰ | 免费不卡在线视频| 久久午夜色播影院免费高清| 久久人人爽人人爽爽久久| 久久亚洲精品网站| 欧美日韩亚洲综合| 国产真实久久| 一区二区三区蜜桃网| 欧美中在线观看| 99xxxx成人网| 嫩草国产精品入口| 国产精品美女久久| 亚洲精品美女| 亚洲观看高清完整版在线观看| 久热精品视频在线观看| 欧美jjzz| 亚洲欧美自拍偷拍| 欧美精品成人一区二区在线观看 | 亚洲午夜国产成人av电影男同| 午夜亚洲一区| 国产精品五月天| 在线亚洲国产精品网站| 久久香蕉国产线看观看av| 日韩视频在线观看一区二区| 久久精品中文字幕一区| 国产精品亚洲综合久久| 欧美无乱码久久久免费午夜一区 | 国产精品国产自产拍高清av| 亚洲高清一区二区三区| 欧美大尺度在线观看| 免费高清在线一区| 亚洲第一精品久久忘忧草社区| 欧美亚洲一级片| 欧美一区二区三区婷婷月色 | 久久性色av| 欧美日韩国产大片| 一本久道久久综合婷婷鲸鱼 | 狠狠色狠狠色综合日日小说| 欧美一级黄色网| 久久久精品网| 国产精品一区二区三区久久 | 欧美国产在线观看| 久久国产精品99久久久久久老狼| 99视频热这里只有精品免费| 最新国产成人在线观看| 欧美日韩国产限制| 久久激情视频久久| 欧美成年人在线观看| 亚洲欧美另类在线| 久久免费一区| 亚洲综合社区| 欧美刺激性大交免费视频 | 欧美黑人在线观看| 欧美在线免费一级片| 欧美大片一区二区三区| 欧美亚洲专区| 欧美午夜激情在线| 亚洲国产二区| 亚洲高清视频在线观看| 99视频一区二区三区| 午夜精品婷婷| 亚洲在线免费| 欧美国产免费| 欧美本精品男人aⅴ天堂| 影音先锋日韩精品| 香蕉亚洲视频| 久久久精品日韩| 国产综合自拍| 久久久久久尹人网香蕉| 免费亚洲视频| 91久久精品美女高潮| 欧美风情在线观看| 91久久精品国产91性色|