zoukankan      html  css  js  c++  java
  • 见到的一篇IOCP流程 自己用demo实现了一下, 简单照抄,改动了一点点

    要分析的实例分为两个线程:


    分别是主线程(MAIN),还有一个是创建的线程(ServerThread)


    1.主函数完成初始化工作:
      1.1: (主线程)HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);    创建完成端口对象
      1.2: (主线程)::CreateThread(NULL, 0, ServerThread, (LPVOID)hCompletion, 0, 0);  创建线程用于接收等
      1.3:(主线程)调用socket(),SOCKADDR_IN,bind(),listen(),初始化套接字
      1.4: (线程函数)HANDLE hCompletion = (HANDLE)lpParam;   通过线程参数得到完成端口对象
      1.5: (线程函数) while(TRUE)     定义循环  循环等待套接字上发生事件
      1.6:(线程函数) ::GetQueuedCompletionStatus() 在关联到此完成端口的所有套节字上等待I/O完成
      1.7: (主线程) SOCKADDR_IN saRemote; SOCKET sNew = ::accept(sListen, (sockaddr*)&saRemote, &nRemoteLen); 为新连接建立结构并等待连接请求


    2.有连接发生:
      2.1: (主线程while循环中) PPER_HANDLE_DATA pPerHandle = (PPER_HANDLE_DATA)::GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
                               创建PPER_HANDLE_DATA结构 
      2.2: (主线程while循环中) ::CreateIoCompletionPort((HANDLE)pPerHandle->s, hCompletion, (DWORD)pPerHandle, 0);
        完成 完成端口 与 套接字关联
      2.3: (主线程while循环中)    给pPerIO结构   添加类型
    PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
    pPerIO->nOperationType = OP_READ;
    WSABUF buf;
    buf.buf = pPerIO->buf;
    buf.len = BUFFER_SIZE;
    DWORD dwRecv;
    DWORD dwFlags = 0;
      2.4: (主线程while循环中) ::WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL);     发送异步接收请求
      2.5: (主线程while循环中)  回到WHILE循环accept()函数处  等待新连接
      2.6: (线程函数while循环中)GetQueuedCompletionStatus() 此时I/O完成 开始处理消息
      2.7: (线程函数while循环中)pPerIO->nOperationType  通过类型判断  消息类型
      2.7:(线程函数while循环中)打印接收的消息  并在此投递  一个完成端口
    pPerIO->buf[dwTrans] = '\0';
    printf(pPerIO -> buf);

    WSABUF buf;
    buf.buf = pPerIO->buf ;
    buf.len = BUFFER_SIZE;
    pPerIO->nOperationType = OP_READ;
    DWORD nFlags = 0;
    printf("12\n");
    ::WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);
      2.8:(线程函数while循环中)  由于又有端口I/O完成 ::GetQueuedCompletionStatus()函数  继续判断并处理
      2.9:(线程函数while循环中)  由于没有数据 GetQueuedCompletionStatus()返回值为错误  调用一下函数关闭
    ::closesocket(pPerHandle->s);
    ::GlobalFree(pPerHandle);
    ::GlobalFree(pPerIO);

      2.10:(线程函数while循环中)  在此回到while循环 调用::GetQueuedCompletionStatus()函数  继续等待


    // iocpTP.cpp : Defines the entry point for the console application.
    //


    #include "stdafx.h"


    #include <stdio.h>
    #include <windows.h>


    // 初始化Winsock库
    #include <winsock2.h>
    #pragma comment(lib,"WS2_32.lib") // 






    #define BUFFER_SIZE 1024


    typedef struct _PER_HANDLE_DATA // per-handle数据
    {
    SOCKET s; // 对应的套节字句柄
    sockaddr_in addr;// 客户方地址
    } PER_HANDLE_DATA, *PPER_HANDLE_DATA;




    typedef struct _PER_IO_DATA // per-I/O数据
    {
    OVERLAPPED ol;// 重叠结构
    char buf[BUFFER_SIZE];// 数据缓冲区
    int nOperationType;// 操作类型
    #define OP_READ   1
    #define OP_WRITE  2
    #define OP_ACCEPT 3
    } PER_IO_DATA, *PPER_IO_DATA;




    DWORD WINAPI ServerThread(LPVOID lpParam)
    {
    // 得到完成端口对象句柄
    HANDLE hCompletion = (HANDLE)lpParam;
    printf("ServerThread Processor\n");
    DWORD dwTrans;
    PPER_HANDLE_DATA pPerHandle;
    PPER_IO_DATA pPerIO;
    while(TRUE)
    {
    // 在关联到此完成端口的所有套节字上等待I/O完成
    printf("wait GetQueuedCompletionStatus  Done \n");
    BOOL bOK = ::GetQueuedCompletionStatus(hCompletion, 
    &dwTrans, (LPDWORD)&pPerHandle, (LPOVERLAPPED*)&pPerIO, WSA_INFINITE);
    if(!bOK) // 在此套节字上有错误发生
    {
    printf("9\n");
    ::closesocket(pPerHandle->s);
    ::GlobalFree(pPerHandle);
    ::GlobalFree(pPerIO);
    continue;
    }

    if(dwTrans == 0 &&// 套节字被对方关闭
    (pPerIO->nOperationType == OP_READ || pPerIO->nOperationType == OP_WRITE))

    {
    printf("10\n");
    ::closesocket(pPerHandle->s);
    ::GlobalFree(pPerHandle);
    ::GlobalFree(pPerIO);
    continue;
    }
    printf("11\n");
    switch(pPerIO->nOperationType)// 通过per-I/O数据中的nOperationType域查看什么I/O请求完成了
    {
    case OP_READ: // 完成一个接收请求
    {
    pPerIO->buf[dwTrans] = '\0';
    printf(pPerIO -> buf);

    // 继续投递接收I/O请求
    WSABUF buf;
    buf.buf = pPerIO->buf ;
    buf.len = BUFFER_SIZE;
    pPerIO->nOperationType = OP_READ;


    DWORD nFlags = 0;
    printf("12\n");
    ::WSARecv(pPerHandle->s, &buf, 1, &dwTrans, &nFlags, &pPerIO->ol, NULL);

    }
    break;
    case OP_WRITE: // 本例中没有投递这些类型的I/O请求
    {
    WSABUF buf;
    buf.buf = pPerIO->buf ;
    buf.len = BUFFER_SIZE;
    pPerIO->nOperationType = OP_READ;
    DWORD nFlags = 0;
    ::WSASend(pPerHandle->s, &buf, 1, &dwTrans, nFlags, &pPerIO->ol, NULL);
    }
    break;
    case OP_ACCEPT:
    {
    }
    break;
    }
    }
    return 0;
    }




    void main()
    {
    // 初始化WS2_32.dll
    BYTE minorVer = 0x02;
    BYTE majorVer = 0x02;
    WSADATA wsaData;
    WORD sockVersion = MAKEWORD(minorVer, majorVer);
    if(::WSAStartup(sockVersion, &wsaData) != 0)
    {
    }
    int nPort = 5000;
    // 创建完成端口对象,创建工作线程处理完成端口对象中事件
    printf("Init NetWork\n");
    HANDLE hCompletion = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
    printf("CreateIoCompletionPort Done\n");
    ::CreateThread(NULL, 0, ServerThread, (LPVOID)hCompletion, 0, 0);
    printf("Create Server Thread \n");
    // 创建监听套节字,绑定到本地地址,开始监听
    SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, 0);
    SOCKADDR_IN si;
    si.sin_family = AF_INET;
    si.sin_port = ::ntohs(nPort);
    si.sin_addr.S_un.S_addr = INADDR_ANY;
    ::bind(sListen, (sockaddr*)&si, sizeof(si));
    ::listen(sListen, 5);


    printf("Start Listen \n");
    // 循环处理到来的连接
    while(TRUE)
    {
    // 等待接受未决的连接请求
    printf("Wait for Connect...\n");
    SOCKADDR_IN saRemote;
    int nRemoteLen = sizeof(saRemote);
    SOCKET sNew = ::accept(sListen, (sockaddr*)&saRemote, &nRemoteLen);


    // 接受到新连接之后,为它创建一个per-handle数据,并将它们关联到完成端口对象。
    PPER_HANDLE_DATA pPerHandle = 
    (PPER_HANDLE_DATA)::GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
    pPerHandle->s = sNew;
    memcpy(&pPerHandle->addr, &saRemote, nRemoteLen);
    ::CreateIoCompletionPort((HANDLE)pPerHandle->s, hCompletion, (DWORD)pPerHandle, 0);
    printf("Accept connect , assigned a CreateIoCompletionPort \n");
    // 投递一个接收请求
    PPER_IO_DATA pPerIO = (PPER_IO_DATA)::GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
    pPerIO->nOperationType = OP_READ;
    WSABUF buf;
    buf.buf = pPerIO->buf;
    buf.len = BUFFER_SIZE;
    DWORD dwRecv;
    DWORD dwFlags = 0;
    printf(" Mail a request!!! \n");
    ::WSARecv(pPerHandle->s, &buf, 1, &dwRecv, &dwFlags, &pPerIO->ol, NULL);
    }


    ::WSACleanup();
    }


    测试程序:

    //////////////////////////////////////////////////////////
    // TCPClient.cppÎļþ
    #include <stdio.h>
    #include <winsock2.h>
    #pragma comment(lib, "ws2_32.lib")


    int main()
    {
    BYTE minorVer = 0x02;
    BYTE majorVer = 0x02;
    //WS2_32.dll
    WSADATA wsaData;
    WORD sockVersion = MAKEWORD(minorVer, majorVer);
    if(::WSAStartup(sockVersion, &wsaData) != 0)
    {
    exit(0);
    }


    // ´´½¨Ì×½Ú×Ö
    SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(s == INVALID_SOCKET)
    {
    printf(" Failed socket() \n");
    return 0;
    }

    // Ò²¿ÉÒÔÔÚÕâÀïµ÷ÓÃbindº¯Êý°ó¶¨Ò»¸ö±¾µØµØÖ·
    // ·ñÔòϵͳ½«»á×Ô¶¯°²ÅÅ

    // ÌîдԶ³ÌµØÖ·ÐÅÏ¢
    sockaddr_in servAddr; 
    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(5000);
    // ×¢Ò⣬ÕâÀïÒªÌîд·þÎñÆ÷³ÌÐò£¨TCPServer³ÌÐò£©ËùÔÚ»úÆ÷µÄIPµØÖ·
    // Èç¹ûÄãµÄ¼ÆËã»úûÓÐÁªÍø£¬Ö±½ÓʹÓÃ127.0.0.1¼´¿É
    servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

    if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
    {
    printf(" Failed connect() \n");
    return 0;
    }

    // ·¢ËÍÊý¾Ý
    send(s,"dddd",sizeof("dddd"),0);
    // ½ÓÊÕÊý¾Ý
    char buff[256];
    int nRecv = ::recv(s, buff, 256, 0);
    if(nRecv > 0)
    {
    buff[nRecv] = '\0';
    printf(" ½ÓÊÕµ½Êý¾Ý£º%s", buff);
    }

    // ¹Ø±ÕÌ×½Ú×Ö
    ::closesocket(s);


    ::WSACleanup();
    return 0;
    }

  • 相关阅读:
    Two Sum II
    Subarray Sum
    Intersection of Two Arrays
    Reorder List
    Convert Sorted List to Binary Search Tree
    Remove Duplicates from Sorted List II
    Partition List
    Linked List Cycle II
    Sort List
    struts2结果跳转和参数获取
  • 原文地址:https://www.cnblogs.com/eaglezzb/p/4176558.html
Copyright © 2011-2022 走看看