套接字I/O模型之三--WSAEventSelect

时间:2022-05-17 00:00:46

WSAEventSelect是WinSock提供的一个有用的异步I/O模型,和WSAAsyncSelect(MFC的CAsyncSocket类就是采用的该模型)类似,允许用用程序在一个或多个套接字(是一个套接字组)上接收以事件为基础的网络事件的通知。

 

一、要了解次I/O模型首先可以从函数WSAEventSelect的原型开始

int WSAEventSelect(SOCKET s,            
                         WSAEVENT
hEventObject,
                         long
lNetworkEvents );

该函数把一个套接字和发生在该套接字上的网络事件与一个事件对象关联起来了,套接字和套接字上的网络事件在这就不说了。对于第二个参数hEventObjectWSAEVENT类型事件的一个句柄,可以通过WSACreateEvent取得。

 

一个事件我们应该知道有两种状态,signaled(有信号),nonsignaled(无信号状态)。在这里的事件的在与之关联的套接字发上了网络事件,事件就会被置于有信号状态;刚开始创建事件是都自动置于无信号状态,一旦与之关联的套接字上发生了网络事件,该事件就被置于有信号状态。

 

 

二、问题是我们怎样才能找到一个事件是不是处在有信号状态还是在无信号状态的呢?

 

在线程之间的同步时候我们经常用到一个函数WaitForSingleObject()。由于WSAEvetnSelect提供的多套接字上的网络事件的通知,我们用到函数WSAWaitForMultipleEvents(),下面看看次函数的原型:

DWORD WSAWaitForMultipleEvents(
                       DWORD
cEvents,               //事件的个数
                    const WSAEVENT*
lphEvents, // 指向事件组的指针
                    BOOL
fWaitAll,              //等待所有的事件还是任意一个事件
                    DWORD
dwTimeout,            //等待时间
                    BOOL
fAlertable);           // 一般设置为fasle,此处该参数没用

 

若WSAWaitForMultipleEvents调用时,对应的事件对象收到网络事件的通知被置于有信号状态,就会返回一个index值(设fWaitAll设定为FALSE),当然返回的并不是在事件组的索引号,而是要减去一个WSA_WAIT_EVENT_0之后才是事件对象索引。

              例如:index = WSAWaitForMultipleEvents(...);

   MyEvent = EventArray[index-WSA_WAIT_EVENT_0];

 

 

三、知道了发生网络事件的套接字和网络事件以后,我们接下来就知道的肯定就是具体发生了什么网络事件,并予以相应的动作。

 

现在我们有必要了解下函数WSAEnumNetworkEvents()其原型如下:

   int WSAEnumNetworkEvents(
                                  SOCKET
s,                //套接字句柄
                                 WSAEVENT
hEventObject,    //事件句柄
                                LPWSANETWORKEVENTS
lpNetworkEvents);
    参数说明一:套接字句柄没有说明的必要。

参数说明二:关于事件句柄这里可以不指定,不指定的时候我们有必要调用函数WSAResetEvent()讲该事件置于无信号状态,要是指定的话WSAEnumNetworkEvents()会自动将事件还原为无信号状态。

参数说明三:lpNetworkEvents为指向下面结构的指针,为输出参数。

typedef struct _WSANETWORKEVENTS {
                            long lNetworkEvents;
                            int iErrorCode[FD_MAX_EVENTS];
                           } WSANETWORKEVENTS, *LPWSANETWORKEVENTS;

该结构为了指明发生在套接字上的网络事件类型和可能发生的错误代码。

                  注意:一个事件变为有信号状态可能同时发生多个网络事件。

例如以下调用形式的代码:

if (NetworkEvents.lNetworkEvents & FD_CLOSE)
      {
       if (NetworkEvents.iErrorCode[FD_CLOSE_BIT] != 0)
        {
           printf("FD_CLOSE failed with error %d/n", NetworkEvents.iErrorCode[FD_CLOSE_BIT]);
            break;
         }

 printf("Closing socket information %d/n", SocketArray[Event - WSA_WAIT_EVENT_0]->Socket);

      FreeSocketInformation(Event - WSA_WAIT_EVENT_0);
    }

 

 

优点:

    在于概念简单,不需要窗口环境。

缺点:

     在于每次只能等待64个事件,这就是说在处理多天64个的SOCKET时必须组织一个线程池。如需处理大量的SOCKET连接,此模型的伸缩性就不如重叠模型。