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

隨筆 - 298  文章 - 377  trackbacks - 0
<2013年6月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

常用鏈接

留言簿(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>
              亚洲精选91| 国产精品视频yy9099| 一本久久知道综合久久| 亚洲精品免费看| 亚洲欧洲一区二区天堂久久 | 亚洲二区在线观看| 国产日韩一区欧美| 黄色亚洲在线| 亚洲精品精选| 亚洲欧美日本视频在线观看| 久久久久久成人| 欧美福利一区二区| 亚洲开发第一视频在线播放| 亚洲一区激情| 裸体丰满少妇做受久久99精品 | 久久福利毛片| 免费观看成人| 国产精品日韩久久久| 亚洲国产高清高潮精品美女| 亚洲一区二区三区欧美| 久久亚洲私人国产精品va| 亚洲精品美女| 欧美一区二区三区四区高清 | 中国成人黄色视屏| 久久久999| 亚洲美女91| 久久久噜噜噜久久| 欧美亚一区二区| 亚洲激情综合| 久久久久91| 亚洲午夜精品一区二区| 欧美成人免费在线| 韩国av一区二区三区四区| 亚洲欧洲av一区二区三区久久| 亚洲国产成人精品久久| 西西裸体人体做爰大胆久久久| 欧美精品午夜| 亚洲国产欧美久久| 久久精品视频网| 一本到高清视频免费精品| 美女亚洲精品| 精品99视频| 性欧美video另类hd性玩具| 最新中文字幕亚洲| 久久在线观看视频| 国产网站欧美日韩免费精品在线观看| 一本一本久久| 亚洲国产一区二区视频| 久久久999精品免费| 国产精品久久久久国产精品日日| 亚洲精品一区在线观看| 欧美风情在线| 裸体素人女欧美日韩| 黄色日韩在线| 久久久久久尹人网香蕉| 欧美一区二区三区四区在线观看地址 | 亚洲精品在线免费| 欧美激情第8页| 老司机一区二区三区| 在线观看欧美日本| 久久综合综合久久综合| 久久久www免费人成黑人精品 | 99国内精品久久| 欧美精品一区二区三区在线播放| 亚洲欧洲一区二区三区久久| 欧美国产一区二区| 欧美福利专区| 国产精品99久久久久久久女警| 99视频在线观看一区三区| 欧美午夜精品久久久| 亚洲欧美日韩中文视频| 午夜日韩福利| 在线成人免费观看| 亚洲电影观看| 欧美日韩一区二区在线播放| 亚洲一区二区三区影院| 亚洲免费在线精品一区| 黄色精品在线看| 亚洲国产精品悠悠久久琪琪| 欧美欧美全黄| 亚洲专区一区二区三区| 性欧美超级视频| 亚洲大片精品永久免费| 亚洲精品一线二线三线无人区| 欧美天天影院| 久久嫩草精品久久久久| 欧美成人在线影院| 午夜精品福利电影| 久久一区二区三区四区五区| 一本色道久久综合狠狠躁篇的优点| 中文欧美日韩| 亚洲精品乱码久久久久久按摩观| 中文在线不卡视频| 亚洲国产成人精品久久| 一本久久a久久精品亚洲| 在线看欧美日韩| 一区二区久久| 亚洲高清自拍| 午夜精品理论片| 亚洲精品在线视频观看| 欧美亚洲一区二区三区| 一区二区欧美日韩| 久久伊人亚洲| 久久av一区二区三区| 欧美日本亚洲| 欧美激情2020午夜免费观看| 国产午夜亚洲精品羞羞网站| 夜夜嗨av色一区二区不卡| 亚洲精品1区2区| 久久九九国产| 欧美一区成人| 国产精品成人一区二区三区夜夜夜 | 先锋亚洲精品| 亚洲精选91| 久久久久久国产精品mv| 亚洲欧美日韩综合| 欧美另类久久久品| 亚洲国产高清一区| 狠狠综合久久av一区二区小说 | 欧美国产亚洲视频| 模特精品裸拍一区| 国产亚洲在线| 亚洲制服av| 亚洲淫片在线视频| 欧美精品系列| 亚洲国产天堂久久综合网| 亚洲第一精品夜夜躁人人躁| 欧美综合国产精品久久丁香| 午夜亚洲性色视频| 国产精品啊啊啊| 日韩天天综合| 一本色道久久综合亚洲精品不 | 欧美视频免费在线| 最新中文字幕一区二区三区| 亚洲国产日韩欧美在线99| 久久久国产精品亚洲一区| 久久久久久一区二区| 黄色成人91| 蜜桃伊人久久| 欧美激情精品久久久久久免费印度 | 国产精品a久久久久久| 亚洲人成网站在线观看播放| 亚洲精品乱码久久久久久日本蜜臀 | 亚洲视频网在线直播| 亚洲欧美日韩另类精品一区二区三区| 欧美日韩一区二区三区视频| 中日韩视频在线观看| 亚洲一区二区三区四区中文 | 国产免费成人| 午夜精品一区二区三区在线播放| 欧美在线视频观看| 黄色成人在线网址| 久久午夜精品一区二区| 六月天综合网| **网站欧美大片在线观看| 美女亚洲精品| 夜夜嗨av一区二区三区四季av| 亚洲欧美日韩国产精品| 国产一区日韩欧美| 久久久欧美一区二区| 最新亚洲视频| 篠田优中文在线播放第一区| 久久精品av麻豆的观看方式| 欧美国产日韩精品免费观看| 一本综合精品| 国内精品视频久久| 欧美精选午夜久久久乱码6080| 在线午夜精品| 欧美h视频在线| 亚洲永久免费视频| 影音先锋久久资源网| 欧美精品一区二区三区高清aⅴ| 一区二区三区|亚洲午夜| 久久亚洲综合| 亚洲免费网站| 亚洲国产一区在线| 国产精品久久久久久av下载红粉 | 亚洲国产视频一区二区| 欧美性大战久久久久久久| 欧美伊人久久久久久午夜久久久久| 欧美成人资源| 欧美一级免费视频| 亚洲每日在线| 国产专区欧美精品| 欧美视频一区二区| 男女视频一区二区| 久久国产精品久久国产精品| 国产精品99久久久久久人| 亚洲激情视频在线| 久久综合精品国产一区二区三区| 亚洲视频在线观看| 亚洲韩国青草视频| 国产一区高清视频| 国产精品扒开腿爽爽爽视频| 欧美精品国产一区二区| 蜜臀av性久久久久蜜臀aⅴ四虎| 久久精品一区二区三区四区| 亚洲欧美一级二级三级| 一区二区三区高清视频在线观看| 亚洲二区在线视频|