Winsock的套接字I/O模型

套接字I/O模型共有五种类型,如下:

  select(选择) 
  WSAAsyncSelect(异步选择)
  WSAEventSelect(事件选择)
  overlapped(重叠)
  completion port(完成端口)

 

*WSAAsyncSelect

      Winsock通过WSAAsyncSelect()自动地设置套接字处于非阻塞方式。使用WindowsSockets实现Windows网络程序设计 的关键就是它提供了对网络事件基于消息的异步存取,用于注册应用程序感兴趣的网络事件。它请求Windows Sockets DLL在检测到套接字上发生的网络事件时,向窗口发送一个消息。

 int PASCAL FAR WSAAsyncSelect(SOCKET s,HWND hWnd,unsigned int wMsg,long lEvent);
hWnd: 窗口句柄
wMsg:需要发送的消息
lEvent:事件(以下为事件的内容)
值: 含义:
FD_READ 期望在套接字上收到数据(即读准备好)时接到通知
FD_WRITE 期望在套接字上可发送数据(即写准备好)时接到通知
FD_OOB 期望在套接字上有带外数据到达时接到通知
FD_ACCEPT 期望在套接字上有外来连接时接到通知
FD_CONNECT 期望在套接字连接建立完成时接到通知
FD_CLOSE 期望在套接字关闭时接到通知

       进行异步选择使用WSAAsyncSelect()函数时,有以下几点需要引起特别的注意:
  .连续使用两次 WSAAsyncSelect()函数时,只有第二次设置的事件有效,如:
           WSAAsyncSelect(s,hwnd,wMsg1,FD_READ);
           WSAAsyncSelect(s,hwnd,wMsg2,FD_CLOSE);
        这样只有当FD_CLOSE事件发生时才会发送wMsg2消息。
  .可以在设置过异步选择后通过再次调用 WSAAsyncSelect(s,hwnd,0,0);的形式取消在套接字上所设置的异步事件。
  .Windows Sockets DLL在一个网络事件发生后,通常只会给相应的应用程序发送一个消息,而不能发送多个消息。但通过使用一些函数隐式地允许重发此事件的消息,这样就可能再 次接收到相应的消息。
  .在调用过closesocket()函数关闭套接字之后不会再发生FD_CLOSE事件。


     对UDP协议,这些网络事件主要为:
      FD_READ   期望在套接字收到数据(即读准备好)时接收通知;
      FD_WRITE 期望在套接字可发送数(即写准备好)时接收通知;
    FD_CLOSE 期望在套接字关闭时接电通知
   消息变量wParam指示发生网络事件的套接字,变量1Param的低字节描述发生的网络事件,高字包含错误码。如在窗口函数的消息循环中均加一个分 支:
int ok=sizeof(SOCKADDR);
case wMsg;
switch(1Param)
{
    case FD_READ:  //套接字上读数据 
    if(recvfrom(sr.lpPlayData[j],dwDataSize,0,(struct sockaddr FAR*)&there1,
     (int FAR*)&ok)==SOCKET_ERROR0) {
                MessageBox(hwnd,“数据接收失败!”,“”,MB_OK);
                return(FALSE);
       }
    case FD_WRITE:    //套接字上写数据
  }
break;

 

 

*WSAEventSelect
      事件通知模型 要求在程序中针对使用的每个套接字创建一个事件对象,然后通过事件模式通知程序其套接字是否收到或发送的信息。一般来说这种模式,一般就是通过类似调用 waitformultipleObject一样在一个线程中等待信号事件来,来了就处理。具体调用的函数如下:

    创建WSACreateEvent函数.该函数的返回值是一个创建好的事件对象句柄。事件对象句柄完后,接下来将其与某个套接字关联在一起,同时注册自 己感兴趣的网络事件类型,方法是调用WSAEventSelect函数,对它的定义如下:

   int WSAEventSelect (
              SOCKET s,                              //需要非阻塞处理的套接字
              WSAEVENT hEventObject,    //WSACreateEvent 创建来的,关联到socket
              long lNetworkEvents     
               );
    lNetworkEvents,对应一个“位掩码”,用于指定应用程序感兴趣的各种网络事件类型的一个组合。要想获知对这些事件类型的详细说明,请参考早 先讨论过的WSAAsyncSelect I/O模型。
      为WSAEventSelect创建的事件拥有两种工作状态,以及两种工作模式。
    两种工作状态分别是“已传信”(signaled)和 “未传信”(nonsignaled)。
    工作模式则包括“人工”(manual reset)和“自动”(auto reset)。

      WSACreateEvent缺省时其信号状态为0,且为人工设置,当网络事件触发了与一个套接字关联在一起的事件对象,其事件信号置1。在完成了一个 I/O请求的处理之后,需要调用WSAResetEvent复位处理(置信号为0)。
     一个套接字同一个事件对象句柄关联在一起后,应用程序便可开始I/O处理;方法是等待网络事件触发事件对象句柄的工作状态。
     一般而言,在等待网络传来事件时,类似WaitforMultipleObject,其WSAWaitForMultipleEvents函数的设计宗旨 便是用来等待一个或多个事件对象句柄,并在事先指定的一个或所有句柄进入有信号状态后,或在超过了一个规定的时间周期后,立即返回(线程往往在这里死 等)。

   下面是 WSAWaitForMultipleEvents函数的定义:
DWORD WSAWaitForMultipleEvents(
  DWORD cEvents ,                 
  const WSAEVENT FAR *lphEvents
  BOOL fWaitAll ,                 
  DWORD dwTimeOUT ,               
  BOOL fAlertable                
);

其用法和WaitForMultipleObject类 似。
cEvents和lphEvents参数定义了由WSAEVENT对象构成的一个数组。在这个数组中,cEvents指定的是事件对象的数 量,而lphEvents对应的是一个指针,用于直接引用该数组。
     要注意的是, WSAWaitForMultipleEvents只能支持由WSA_MAXIMUM_WAIT_EVENTS对象规定的一个最大值,在此定义成64个。 故该I/O模型一次最多都只能支持64个套接字。假如想让这个模型同时管理不止64个套接字,必须创建更多的工作者线程,以便等待更多的事件对象。

fWaitAl l 参数指定了WSAWaitForMultiple Events如何等待在事件数组中的对象。
   =TRUE,那 么只有等lphEvents数组内包含的所有事件对象都处于有信号状态,函数才会返回;

   =FALSE,任一个事件对象进入有信号时,函数就会返回。

 dwTimeout参数规定了 WSAWaitForMultipleEvents最多可等待一个网络事件发生有多长时间。超过规定的时间,函数就会立即返回。并返回 WSA_WAIT_TIMEOUT。如dwsTimeout设为WSA_INFIN ITE(永远等待),那么根据fWaiiAll或等待一个网络事件或所有网络事件都传信号后,才能从该函数退出。
 fAlertable,缺省设 为FALSE。主要用于在重叠式I/O模型中.

  当设置fWaiAll=false,WaitForMultipleObject再有 网络事件时,会返回一个值,指出造成函数返回的事件对象。根据WSAWaitForMultipleEvents的返回值,减去预定义值 WSA_WAIT_EVENT_0,得到具体的引用值(即索引位置),程序便可用事件数组中已发信号的事件,检索与那个事件对应的套接字,知道了造成网络 事件的套接字后,调用 WSAEnumNetworkEvents函数,调查发生了什么类型的网络事件。该函数定义如下:
int WSAEnumNetworkEvents (
  SOCKET s ,                                      // 检索该套接字
  WSAEVENT hEventObject ,             
  LPWSANETWORKEVENTS lpNetworkEvents 
);
    hEventObject参数则是可选的;它指定了一个事件句柄,对应于打算重设的那个事件对象。由于我们的事件对象处在一个有信号状态,所以可将它传 入,令其自动成为无信号状态。
    也可以采用使用 WSAResetEvent 函数复位事件信号。
   lpNetworkEvents,就是返回的结果信息,它是一个指向WSANETWORKEVENTS结构的指针,用于接收套接字上发生的网络事件类型以 及可能出现的任何错误代码。

其WSANETWORKEVENTS结构的定义:
typedef struct _WSANETWORKEVENTS
{
     long lNetworkEvents;
     int iErrorCode[FD_MAX_EVENTS];
} WSANETWORKEVENTS, FAR * LPWSANETWORKEVENTS;
lNetworkEvents参数指定了一个值,对应于套接字上发生的所有网络事件类型。
      注意一个事件进入置1(有信号)状态时,可能会同时发生多个网络事件类型。如,一个忙的服务器可能同时收到FD_READ和FD_WRITE通知。 iErrorCode参数指定的是一个错误代码数组,同lNetworkEvents中的事件关联在一起。针对每个网络事件类型,都存在着一个特殊的事件 索引,名字与事件类型的名字类似,只是要在事件名字后面添加一个“ _BIT”后缀字串即可。如,对FD_READ事件类型来说,iErrorCode数组的索引标识符便是FD_READ_BIT。

你可能感兴趣的:(Winsock的套接字I/O模型)