AcceptEx函式與完成埠的結合使用例子
阿新 • • 發佈:2018-12-21
這是在學《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();}