AcceptEx函數與完成端口的結合使用例子
阿新 • • 發佈:2019-03-11
gre lean edit 調用 targe 老師 oda close tle
分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!http://www.captainbed.net
這是在學《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();
}
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!http://www.captainbed.net
AcceptEx函數與完成端口的結合使用例子