zoukankan      html  css  js  c++  java
  • AcceptEx函数与完成端口的结合使用例子

    这是在学《Windows网络编程(第二版)》第六章时制作的一个例子
    由于书中没有给出简洁的例子,本人在学这里时就费了很多时间。
    现在把完成的代码贴出来,供大家参考。
    下面包括了主程序部分,工作线程在(2)中贴出,由于代码太长。
    本程序在VS2003编译器编译运行。在6.0下可能需要稍加修改。
    
    #include <iostream>
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <mswsock.h>    //微软扩展的类库
    
    using namespace std;
    #define SEND 0
    #define RECV 1
    #define ACCEPT 2
    
    #define DATA_LENGTH 1000
    //单句柄数据定义
    typedef struct _PER_HANDLE_DATA
    {
        SOCKET socket;    //相关的套接字
        SOCKADDR_STORAGE clientAddr;    //客户端的地址
    }PER_HANDLE_DATA,*LPPER_HANDLE_DATA;
    
    //但IO操作数据
    typedef struct{
        OVERLAPPED overlapped;
        WSABUF buffer;    //一个数据缓冲区,用于WSASend/WSARecv中的第二个参数
        char dataBuffer[DATA_LENGTH];    //实际的数据缓冲区
        int dataLength;                    //实际的数据缓冲区长度
        int operatorType;                //操作类型,可以为SEND/RECV两种
        SOCKET client;                    //分别表示发送的字节数和接收的字节数
    }PER_IO_DATA,*LPPER_IO_DATA;
    
    
    void main()
    {
        HANDLE CompletionPort;
        WSADATA data;
        SYSTEM_INFO info;
        SOCKADDR_IN addr;
        SOCKET Listen;
    
        unsigned int i;
        WSAStartup(MAKEWORD(2,2),&data);
    
        //创建一个IO完成端口
        CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
        //确定处理器的数量
        GetSystemInfo(&info);    //创建线城
        for(i=0;i<info.dwNumberOfProcessors * 2;i++)
        {
            //根据处理器的数量创建相应多的处理线程
            HANDLE thread = CreateThread(NULL,0,ServerThread,CompletionPort,0,NULL);
            CloseHandle(thread);
        }
        //创建一个监听套接字(进行重叠操作)
        Listen = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);
        //将监听套接字与完成端口绑定
        LPPER_HANDLE_DATA perDandleData;
        perDandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA));
        perDandleData->socket = Listen;
        CreateIoCompletionPort((HANDLE)Listen,CompletionPort,(ULONG_PTR)perDandleData,0);
    
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(5500);
    
        bind(Listen,(PSOCKADDR)&addr,sizeof(addr));
        listen(Listen,5);
    
        LPFN_ACCEPTEX lpfnAcceptEx = NULL;    //AcceptEx函数指针
        //Accept function GUID
        GUID guidAcceptEx = WSAID_ACCEPTEX;
        //get acceptex function pointer
        DWORD dwBytes = 0;
        if(WSAIoctl(Listen,SIO_GET_EXTENSION_FUNCTION_POINTER,
            &guidAcceptEx,sizeof(guidAcceptEx),&lpfnAcceptEx,sizeof(lpfnAcceptEx),
            &dwBytes,NULL,NULL)==0)
            cout<<"WSAIoctl success..."<<endl;
        else{
            cout<<"WSAIoctl failed..."<<endl;
            switch(WSAGetLastError())
            {
            case WSAENETDOWN:
                cout<<""<<endl;
                break;
            case WSAEFAULT:
                cout<<"WSAEFAULT"<<endl;
                break;
            case WSAEINVAL:
                cout<<"WSAEINVAL"<<endl;
                break;
            case WSAEINPROGRESS:
                cout<<"WSAEINPROGRESS"<<endl;
                break;
            case WSAENOTSOCK:
                cout<<"WSAENOTSOCK"<<endl;
                break;
            case WSAEOPNOTSUPP:
                cout<<"WSAEOPNOTSUPP"<<endl;
                break;
            case WSA_IO_PENDING:
                cout<<"WSA_IO_PENDING"<<endl;
                break;
            case WSAEWOULDBLOCK:
                cout<<"WSAEWOULDBLOCK"<<endl;
                break;
            case WSAENOPROTOOPT:
                cout<<"WSAENOPROTOOPT"<<endl;
                break;
            }
            return;
        }
    
        //while(true)
        //{
            //准备调用 AcceptEx 函数,该函数使用重叠结构并于完成端口连接
            LPPER_IO_DATA perIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_DATA));
            memset(&(perIoData->overlapped),0,sizeof(OVERLAPPED));    
            perIoData->operatorType = ACCEPT;
            //在使用AcceptEx前需要事先重建一个套接字用于其第二个参数。这样目的是节省时间
            //通常可以创建一个套接字库
            perIoData->client = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,0,0,WSA_FLAG_OVERLAPPED);
    
            perIoData->dataLength = DATA_LENGTH;
            DWORD flags = 0;
            
            //调用AcceptEx函数,地址长度需要在原有的上面加上16个字节
            //注意这里使用了重叠模型,该函数的完成将在与完成端口关联的工作线程中处理
            cout<<"Process AcceptEx function wait for client connect..."<<endl;
            int rc = lpfnAcceptEx(Listen,perIoData->client,perIoData->dataBuffer,
                perIoData->dataLength-((sizeof(SOCKADDR_IN)+16)*2),
                sizeof(SOCKADDR_IN)+16,sizeof(SOCKADDR_IN)+16,&dwBytes,
                &(perIoData->overlapped));
            if(rc == FALSE)
            {
                if(WSAGetLastError()!=ERROR_IO_PENDING)
                    cout<<"lpfnAcceptEx failed.."<<endl;
            }
    
            cin>>i;
        closesocket(Listen);
        WSACleanup();
    }

  • 相关阅读:
    POJ 3114 Tarjan+Dijkstra
    278. First Bad Version
    209. Minimum Size Subarray Sum
    154. Find Minimum in Rotated Sorted Array II
    153. Find Minimum in Rotated Sorted Array
    710. Random Pick with Blacklist
    767. Reorganize String
    524. Longest Word in Dictionary through Deleting
    349. Intersection of Two Arrays
    350. Intersection of Two Arrays II
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318513.html
Copyright © 2011-2022 走看看