【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 3922|回复: 0

[算法/加密解密] 手把手教你SOCKET之WSAEventSelect模型

[复制链接]
发表于 2009-3-1 01:58:03 | 显示全部楼层 |阅读模式
WinSock提供了另一个有用的异步I/O模型,即WSAEventSelect事件模型。和WSAAsyncSelect模型类似,它也允许应用程序在一个或多个套接字上接收以事件为基础的网络事件通知。一般来说,由WSAAsyncSelect模型采用的网络事件可以原封不动地移植到新模型,在新模型开发的应用程序中,也能接收和处理所有这些事件。WSAEventSelect模型与WSAAsyncSelect模型的最主要差别在于网络事件会发送到一个事件对象句柄,而不是投递到一个窗口例程,因此,无窗口句柄的工作线程也可以处理事件通知。
WSAEventSelect模型通过WSAEventSelect函数注册要处理的网络事件类型。WSAEventSelect函数声明如下:
int WSAAPI WSAEventSelect (
     SOCKET s, WSAEVENT
     hEventObject,
     long lNetworkEvents
    );
其中参数功能如下:
?    s  一个标识套接字的描述符。
?    hEventObject  一个句柄,用于标识与所提供的FD_XXX网络事件集合相关的一个事件对象。
?    lNetworkEvents  一个屏蔽位,用于指定感兴趣的FD_XXX网络事件组合。
如果应用程序指定的网络事件及其相应的事件对象成功设置,则返回0。否则返回INVALID_SOCKET错误,应用程序可通过WSAGetLastError()函数来获取相应的错误代码。
WSAEventSelect()常用来决定何时进行数据IO操作(如send( )或recv( )),并期望能立即成功。但是一个稳定的应用程序应该做好这样的准备,即事件对象被设置,并且一个WinSock调用以WSAEWOULDBLOCK立即返回。举例来说,有可能发生下述操作序列:
(1)套接字s上到达数据,WinSock设置了WSAEventSelect事件对象。
(2)应用程序进行其他操作。
(3)在进行操作时,应用程序调用了ioctlSocket(s, FIONREAD...)并发现有数据可读。
(4)应用程序调用一个recv(s,...)来读取数据。
(5)最后应用程序等待WSAEventSelect( )所指定的数据对象,该数据对象指出数据可读。
(6)应用程序调用recv(s,...),但以WSAEWOULDBLOCK错误失败。
当成功地记录了网络事件的发生(通过设置内部网络事件记录的相应位),并且将相应的事件对象设置了信号后,不会对该网络事件作进一步的操作,直到应用程序调用了相应的函数显式地重新允许该网络事件及相应事件对象的信号。
网络事件和相应的处理过程如下所示:
? FD_READ  recv( )或recvfrom( )。
? FD_WRITE  send( )或sendto( )。
? FD_OOB  recv( )。
?    FD_ACCEPT  accept()或WSAAccept(),直到返回的错误代码为WSATRY_ AGAIN,指明条件函数返回CF_DEFER。
? FD_CONNECT  NONE。
? FD_CLOSE  NONE。
? FD_QOS  用SIO_GET_QOS命令调用WSAIoctl( )。
? FD_GROUP_QOS  用SIO_GET_GROUP_QOS命令调用WSAIoctl( )。
WSAEventSelect函数返回值的错误代码意义如下:
? WSANOTINITIALISED  在调用本API之前应成功调用WSAStartup( )。
? WSAENETDOWN  网络子系统失效。
? WSAEINVAL  参数中有非法值,或者指定的套接字处于非法状态。
? WSAEINPROGRESS  一个阻塞的WinSock调用正在进行中,或者服务提供者仍在处理一个回调函数。
? WSAENOTSOCK  描述符不是一个套接字。
下面给出WSAEventSelect()模型的编程实现例程。
//===========================================================
//程序清单 WSAEventSelect模型
//示例程序:演示如何使用WSAEventSelect()模型
//编写:     suyu 2005/09
//============================================================
void main(void)
{
   SOCKET Listen;
   SOCKET Accept;
//…省去若干定义
   if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
   {
      printf("WSAStartup() failed with error %d\n", Ret);
      return;
   }
   printf("WSAStartup OK\n");  
   if ((Listen = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
   {
      printf("socket() failed with error %d\n", WSAGetLastError());
      return;
   }
   printf("socket creating OK\n");
   CreateSocketInformation(Listen);
               //选择FD_ACCEPT和FD_CLOSE事件
   if (WSAEventSelect(Listen,EventArray[EventTotal-1], FD_ACCEPT|
FD_CLOSE) == SOCKET_ERROR)
   {
      printf("WSAEventSelect() failed with error %d\n", WSAGetLastError());
      return;
   }
   printf("WSAEventSelect OK\n");
   InternetAddr.sin_family = AF_INET;
   InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
   InternetAddr.sin_port = htons(PORT);

   if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
   {
      printf("bind() failed with error %d\n", WSAGetLastError());
      return;
   }
   if (listen(Listen, 5))
   {
      printf("listen() failed with error %d\n", WSAGetLastError());
      return;
   }
   printf("listen OK\n");
               //循环处理事件
   while(TRUE)
   {
      if ((Event = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE,
         WSA_INFINITE, FALSE)) == WSA_WAIT_FAILED)
      {
         printf("WSAWaitForMultipleEvents error %d\n", WSAGetLastError());
         return;
      }
     if(WSAEnumNetworkEvents(SocketArray[Event-WSA_WAIT_EVENT_0]->
Socket,EventArray[Event-WSA_WAIT_EVENT_0],&NetworkEvents)== SOCKET_ERROR)
      {
         printf("WSAEnumNetworkEvents error %d\n", WSAGetLastError());
         return;
      }
      
if (NetworkEvents.lNetworkEvents & FD_ACCEPT)
{      //FD_ACCEPT事件
         printf("accept new connection... \n");
/*  处理FD_ACCEPT事件,调用accept函数*/
         }

if (NetworkEvents.lNetworkEvents & FD_READ ||
         NetworkEvents.lNetworkEvents & FD_WRITE)
{                  
/* 处理FD_ READ和FD_WRITE事件 */
          }
if (NetworkEvents.lNetworkEvents & FD_CLOSE)
{      /*处理 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);
      }
   }
   return;
}
 点击下载此文件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2024-5-21 23:20

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表