AcceptEx函数与完成端口的结合使用例子

来源:互联网 发布:淘宝店教程 编辑:程序博客网 时间:2024/05/22 06:15
这是在学《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();}

0 0