套接字IO模型(三) WSAEventSelect模型
2008-08-14 22:08
423 查看
WSAEventSelect模型类似WSAAsynSelect模型,但最主要的区别是网络事件发生时会被发送到一个事件对象句柄,而不是发送到一个窗口。这样可能更加的好,对于服务器端的程序来说。
使用步骤如下:
a、 创建事件对象来接收网络事件:
WSAEVENT WSACreateEvent( void );
该函数的返回值为一个事件对象句柄,它具有两种工作状态:已传信(signaled)和未传信(nonsignaled)以及两种工作模式:人工重设(manual reset)和自动重设(auto reset)。默认未未传信的工作状态和人工重设模式。
b、将事件对象与套接字关联,同时注册事件,使事件对象的工作状态从未传信转变未已传信。
int WSAEventSelect( SOCKET s,WSAEVENT hEventObject,long lNetworkEvents );
s为套接字
hEventObject为刚才创建的事件对象句柄
lNetworkEvents为掩码,定义如上面所述
c、I/O处理后,设置事件对象为未传信
BOOL WSAResetEvent( WSAEVENT hEvent );
Hevent为事件对象
成功返回TRUE,失败返回FALSE。
d、等待网络事件来触发事件句柄的工作状态:
DWORD WSAWaitForMultipleEvents( DWORD cEvents,const WSAEVENT FAR * lphEvents, BOOL fWaitAll,DWORD dwTimeout, BOOL fAlertable );
lpEvent为事件句柄数组的指针
cEvent为为事件句柄的数目,其最大值为WSA_MAXIMUM_WAIT_EVENTS
fWaitAll指定等待类型:TRUE:当lphEvent数组重所有事件对象同时有信号时返回;
FALSE:任一事件有信号就返回。
dwTimeout为等待超时(毫秒)
fAlertable为指定函数返回时是否执行完成例程
nIndex=WSAWaitForMultipleEvents(…);
MyEvent=EventArray[Index- WSA_WAIT_EVENT_0];
事 件选择模型也比较简单,实现起来也不是太复杂,它的基本思想是将每个套接字都和一个WSAEVENT对象对应起来,并且在关联的时候指定需要关注的哪些网 络事件。一旦在某个套接字上发生了我们关注的事件(FD_READ和FD_CLOSE),与之相关联的WSAEVENT对象被Signaled。程序定义 了两个全局数组,一个套接字数组,一个WSAEVENT对象数组,其大小都是MAXIMUM_WAIT_OBJECTS(64),两个数组中的元素一一对 应。
同样的,这里的程序没有考虑两个问题,一是不能无条件的调用accept,因为我们支持的并发连接数有限。解决方法是将套接字按 MAXIMUM_WAIT_OBJECTS分组,每MAXIMUM_WAIT_OBJECTS个套接字一组,每一组分配一个工作者线程;或者采用 WSAAccept代替accept,并回调自己定义的Condition Function。第二个问题是没有对连接数为0的情形做特殊处理,程序在连接数为0的时候CPU占用率为100%。
1 SOCKET Socket[WSA_MAXIMUM_WAIT_EVENTS];
2 WSAEVENT Event[WSA_MAXINUM_WAIT_EVENTS];
3 SOCKET Accept, Listen;
5 DWORD EventTotal = 0;
6 DWORD Index;
7
8 //Set up a TCP socket for listening on port 5150
9 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.lNetwoAD)rkEvents & FD_RE
{
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);
}
}
使用步骤如下:
a、 创建事件对象来接收网络事件:
WSAEVENT WSACreateEvent( void );
该函数的返回值为一个事件对象句柄,它具有两种工作状态:已传信(signaled)和未传信(nonsignaled)以及两种工作模式:人工重设(manual reset)和自动重设(auto reset)。默认未未传信的工作状态和人工重设模式。
b、将事件对象与套接字关联,同时注册事件,使事件对象的工作状态从未传信转变未已传信。
int WSAEventSelect( SOCKET s,WSAEVENT hEventObject,long lNetworkEvents );
s为套接字
hEventObject为刚才创建的事件对象句柄
lNetworkEvents为掩码,定义如上面所述
c、I/O处理后,设置事件对象为未传信
BOOL WSAResetEvent( WSAEVENT hEvent );
Hevent为事件对象
成功返回TRUE,失败返回FALSE。
d、等待网络事件来触发事件句柄的工作状态:
DWORD WSAWaitForMultipleEvents( DWORD cEvents,const WSAEVENT FAR * lphEvents, BOOL fWaitAll,DWORD dwTimeout, BOOL fAlertable );
lpEvent为事件句柄数组的指针
cEvent为为事件句柄的数目,其最大值为WSA_MAXIMUM_WAIT_EVENTS
fWaitAll指定等待类型:TRUE:当lphEvent数组重所有事件对象同时有信号时返回;
FALSE:任一事件有信号就返回。
dwTimeout为等待超时(毫秒)
fAlertable为指定函数返回时是否执行完成例程
nIndex=WSAWaitForMultipleEvents(…);
MyEvent=EventArray[Index- WSA_WAIT_EVENT_0];
事 件选择模型也比较简单,实现起来也不是太复杂,它的基本思想是将每个套接字都和一个WSAEVENT对象对应起来,并且在关联的时候指定需要关注的哪些网 络事件。一旦在某个套接字上发生了我们关注的事件(FD_READ和FD_CLOSE),与之相关联的WSAEVENT对象被Signaled。程序定义 了两个全局数组,一个套接字数组,一个WSAEVENT对象数组,其大小都是MAXIMUM_WAIT_OBJECTS(64),两个数组中的元素一一对 应。
同样的,这里的程序没有考虑两个问题,一是不能无条件的调用accept,因为我们支持的并发连接数有限。解决方法是将套接字按 MAXIMUM_WAIT_OBJECTS分组,每MAXIMUM_WAIT_OBJECTS个套接字一组,每一组分配一个工作者线程;或者采用 WSAAccept代替accept,并回调自己定义的Condition Function。第二个问题是没有对连接数为0的情形做特殊处理,程序在连接数为0的时候CPU占用率为100%。
1 SOCKET Socket[WSA_MAXIMUM_WAIT_EVENTS];
2 WSAEVENT Event[WSA_MAXINUM_WAIT_EVENTS];
3 SOCKET Accept, Listen;
5 DWORD EventTotal = 0;
6 DWORD Index;
7
8 //Set up a TCP socket for listening on port 5150
9 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.lNetwoAD)rkEvents & FD_RE
{
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);
}
}
相关文章推荐
- WinSock IO模型 -- WSAEventSelect模型事件触发条件说明
- (转)套接字IO模型(三) WSAEventSelect模型
- winsock IO模型 WSAEventSelect
- 套接字IO模型(三) WSAEventSelect模型
- WinSock IO模型三: WSAEventSelect 事件机制
- 套接字IO模型(三) WSAEventSelect模型
- Winsock IO模型之WSAEventSelect模型
- WSAEventSelect IO复用模型
- IO模型(二)WSAEventSelect--事件选择机制
- 很幽默的讲解六种Socket IO模型 Delphi版本(自己Select查看,WM_SOCKET消息通知,WSAEventSelect自动收取,Overlapped I/O 事件通知模型,Overlapped I/O 完成例程模型,IOCP模型机器人)
- 网络编程五种IO模型之WSAEventSelect模型
- 套接字I/O模型之WSAEventSelect
- 套接字IO模型(三) WSAEventSelect模型
- WinSock IO模型 -- WSAEventSelect模型事件触发条件说明
- winsock IO模型 WSAEventSelect
- 套接字IO模型(三) WSAEventSelect模型
- WSAEventSelect服务器模型
- [置顶] WinSock 异步I/O模型[3]---事件选择 - WSAEventSelect
- WSAEventSelect事件模型函数介绍
- WSAEventSelect模型