1. 程式人生 > >AcceptEx函式與完成埠的結合使用例子

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();}