4.3 WSAEventSelect
该模型把网络事件投递至一个事件对象句柄,而不是一个窗口函数
4.3.1事件通知:
应用程序针对打算使用的套接字,首先创建一个事件对象
WSAEVENT WSACreateEvent( void );
将返回事件句柄对象与套接字关联在一起,同时注册感兴趣的网络事件
int WSAEventSelect( SOCKET s,
WSAEVENT hEventObject, //事件句柄对象
long lNetworkEvents
);
为WSAEventSelect创建的事件有两种状态以及两种工作模式:
工作状态:己传信和未传信
工作模式:人工重设和自动重设
WSACreateEvent最开始用未传信的工作状态和人工重设模式创建事件句柄,随着网络事件触发
事件对象,工作状态便会从"未传信"转变成"己传信",由于事件对象是人工模式创建的,所在
程序在完成了一个I/O处理后,应把事件对象从"己传信"更改为"未传信",用WSAResetEvent函数
BOOL WSAResetEvent( WSAEVENT hEvent);
程序完成对一个事件对象的处理后,应调用WSACloseEvent函数,释放资源
BOOL WSACloseEvent (WSAEVENT hEvent);
4.3.2
套接字与事件对象句柄关联后,程序就应该I/O处理:方法是等待网络事件触发事件对象句柄的
工作状态,WSAWaitForMulipleEvents函数,便是用来等待一个或多个事件对象句柄,并在事先指
定的一个或所有句柄进入"己传信"状态后或超时后,立即返回.
DWORD WSAWaitForMultipleEvents
(DWORD cEvents, //WSAEVENT对象构成的数组里的事件对象数量
const WSAEVENT FAR * lphEvents, //指向事件对象数组
BOOL fWaitAll, //True,所有事件对象变成"己传信"时,返回,否则有一个变就返回
DWORD dwTimeout, //最多一个网络事件发生时,函数的等待时间
BOOL fAlertable //FALSE
);返回造成函数返回的事件对象的索引,从而知道发生在哪个套接字上
例:
Index = WSAWaitForMultipleEvents(....);
MyEvent = EvnetArray[Index-WSA_WAIT_EVENT_0];
接下来,调查发生网络事件的类型(WSAEnumNetworkEvents):
int WSAEnumNetworkEvent(
SOCKET s, //对应产生网络事件的套接字
WSAEVENT hEventObject, //准备置成"未传信"状态的事件句柄
LPWSANETWORKEVENTS lpNetworkEvents //指向 WSANETWORKEVENTS结构,如下:
);
typedef struct _WSANETWORKEVENTS
{
long lNetworkEvents; //对应套接字上发生的所有网络事件类型(可能多个)
int iErrorCode[FD_MAX_EVENTS]; //错误代码数组,同lNetworkEVents关联
//每个错误索引是在事件类型后加'_BIT'
} WSANETWORKEVENTS,FAR* LPWSANETWORKEVENTS;
例:
// Process FD_READ notification
if (NetworkEvents.lNetworkEvents & FD_READ)
{
if(NetworkEvents.iErrorCode[FD_READ_BIT] !=0)
{
//Error
}
}
例:采用WSAEventSelect I/O模型的示范服务器源代码
SOCKET Socket[WSA_MAXIMUM_WAIT_EVENTS];
WSAEVENT Event[WSA_MAXINUM_WAIT_EVENTS];
SOCKET Accept,
Listen;
DWORD EventTotal = 0;
DWORD Index;
//Set up a TCP socket for listening on port 5150
Listen = socket(PF_INET,SOCK_STREAM,0);
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(5150);
bind(Listen,(PSOCKADDR) &InternetAddr,sizeof(InternetAddr));
NewEvent = WSACreateEvent();
WSAEventSelect(Listen,NewEvnet,FD_ACCEPT|FD_CLOSE);
listen(Listen,5);
Socket[EventTotal] = Listen;
Event[EventTotal] = NewEvent;
EventTotal++;
while (TRUE)
{
//Wait for network events on all sockets
Index = WSAWaitForMultipleEvents(EventTotal,EventArray,FALSE,WSA_INFINITE,FALSE);
WSAEnumNewWorkEvents(SocketArray[Index-WSA_WAIT_EVENT_0],
EventArray[Index-WSA_WAIT_EVENT_0],
&NetworkEvents);
//Check for FD_ACCEPT messages
if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
{
if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] !=0)
{
//Error
break;
}
//Accept a new connection and add it to the socket and event lists
Accept = accept(SocketArray[Index-WSA_WAIT_EVENT_0],NULL,NULL);
//We cannot process more than WSA_MAXIMUM_WAIT_EVENTS sockets ,
//so close the accepted socket
if (EventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
printf("........");
closesocket (Accept);
break;
}
NewEvent = WSACreateEvent();
WSAEventSelect(Accept,NewEvent,FD_READ|FD_WRITE|FD_CLOSE);
Event[EventTotal] = NewEvent;
Socket[EventTotal]= Accept;
EventTotal++;
prinrt("Socket %d connect/n",Accept);
}
//Process FD_READ notification
if (NetworkEvents.lNetworkEvents & FD_READ)
{
if (NetworkEvents.iErrorCode[FD_READ_BIT !=0])
{
//Error
break;
}
//Read data from the socket
recv(Socket[Index-WSA_WAIT_EVENT_0],buffer,sizeof(buffer),0);
}
//process FD_WRITE notitication
if (NetworkEvents.lNetworkEvents & FD_WRITE)
{
if (NetworkEvents.iErrorCode[FD_WRITE_BIT] !=0)
{
//Error
break;
}
send(Socket[Index-WSA_WAIT_EVENT_0],buffer,sizeof(buffer),0);
}
if (NetworkEvents.lNetworkEvents & FD_CLOSE)
{
if(NetworkEvents.iErrorCode[FD_CLOSE_BIT] !=0)
{
//Error
break;
}
closesocket (Socket[Index-WSA_WAIT_EVENT_0]);
//Remove socket and associated event from the Socket and Event arrays and
//decrement eventTotal
CompressArrays(Event,Socket,& EventTotal);
}
}