套接字I/O模型(WSAEventSelect模型)详解

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_MAXIMUM_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 );
10
11 InternetAddr.sin_family       = AF_INET;
12 InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
13 InternetAddr.sin_port         = htons( 5150 );
14
15 bind(Listen,(PSOCKADDR) & InternetAddr, sizeof (InternetAddr));
16
17 NewEvent = WSACreateEvent();
18
19 WSAEventSelect(Listen,NewEvnet,FD_ACCEPT | FD_CLOSE);
20
21 listen(Listen, 5 );
22
23 Socket[EventTotal] = Listen;
24 Event[EventTotal] = NewEvent;
25 EventTotal ++ ;
26
27 while (TRUE)
28 {
29      // Wait for network events on all sockets
30      Index = WSAWaitForMultipleEvents(EventTotal,EventArray,FALSE,WSA_INFINITE,FALSE);
31
32     WSAEnumNewWorkEvents(SocketArray[Index - WSA_WAIT_EVENT_0],
33          EventArray[Index - WSA_WAIT_EVENT_0],
34          & NetworkEvents);
35      // Check for FD_ACCEPT messages
36      if ( NetworkEvents.lNetworkEvents & FD_ACCEPT )
37      {
38          if (NetworkEvents.iErrorCode[FD_ACCEPT_BIT] != 0 )
39          {
40              // Error
41              break ;
42          }
43          // Accept a new connection and add it to the socket and event lists
44          Accept = accept(SocketArray[Index-WSA_WAIT_EVENT_0],NULL,NULL) ;
45
46          // We cannot process more than WSA_MAXIMUM_WAIT_EVENTS sockets ,
47          // so close the accepted socket
48          if (EventTotal > WSA_MAXIMUM_WAIT_EVENTS)
49          {
50              printf( " .. " );
51              closesocket (Accept);
52              break ;
53          }
54          NewEvent = WSACreateEvent();
55
56          WSAEventSelect(Accept,NewEvent,FD_READ|FD_WRITE|FD_CLOSE);
57
58          Event[EventTotal] = NewEvent;
59         Socket[EventTotal]= Accept;
60          EventTotal ++ ;
61          prinrt( " Socket %d connect/n " ,Accept);
62      }
63      // Process FD_READ notification
64      if (NetworkEvents.lNetwoAD)rkEvents & FD_R E
65      {
66          if (NetworkEvents.iErrorCode[FD_READ_BIT != 0 ])
67          {
68              // Error
69              break ;
70          }
71
72          // Read data from the socket
73          recv(Socket[Index-WSA_WAIT_EVENT_0],buffer,sizeof(buffer),0);
74      }
75      // process FD_WRITE notitication
76      if ( NetworkEvents.lNetworkEvents & FD_WRITE )
77      {
78          if (NetworkEvents.iErrorCode[FD_WRITE_BIT] != 0 )
79          {
80              // Error
81              break ;
82          }
83          send(Socket[Index-WSA_WAIT_EVENT_0],buffer,sizeof(buffer),0);
84      }
85      if ( NetworkEvents.lNetworkEvents & FD_CLOSE)
86      {
87          if (NetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0 )
88          {
89              // Error
90              break ;
91          }
92          closesocket (Socket[Index - WSA_WAIT_EVENT_0]);
93          // Remove socket and associated event from the Socket and Event arrays and
94          // decrement eventTotal
95          CompressArrays(Event,Socket, & EventTotal);
96      }
97 }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值