异步选择(WSAAsyncSelect):异步选择基本定义

  • 异步选择(WSAAsyncSelect)模型是一个有用的异步 I/O 模型。利用这个模型,应用程序可在一个套接字上,接收以 Windows 消息为基础的网络事件通知。具体的做法是在建好一个套接字后,调用WSAAsyncSelect函数。
  • WSAAsyncSelect模型是Select模型的异步版本,在调用select()函数时,会发生阻塞现象。可以通过select()函数timeout参数,设置函数调用的阻塞时间。在设定的时间内,线程保持等待,直到其中一个或多个套接字满足可读可写的条件时,该函数返回。
  • 该模型的核心即是WSAAsyncSelect函数,该函数是非阻塞的。
  • 要想使用 WSAAsyncSelect 模型,在应用程序中,必须有一个窗口,且该窗口有一个窗口例程函数(WinProc)。
  • 与select模型比较:
  • 相同点:他们都可以对Windows套接字应用程序所使用的多个套接字进行有效的管理。

  • 不同点: 1.WSAAsyncSelect模型是异步的。在应用程序中调用WSAAsyncSelect()函数,通知系统感兴趣的网络事件,该函数立即返回,应用程序继续执行;

  • 2.发生网络事件时,应用程序得到的通知方式不同。Select()函数返回时,说明某个或者某些套接字满足可读可写的条件,应用程序需要使用FD_ISSET宏,判断套接字是否存在可读可写集合中。而对于WSAAsyncSelect模型来说,当网络事件发生时,系统向应用程序发送消息。

  • 3.WSAAsyncSelect模型应用在基于消息的Windos环境下,使用该模型时必须创建窗口。而Select模型广泛应用在Unix系统和Windows系统,使用该模型不需要创建窗口。

  • 4.应用程序调用WSAAsyncSelect()函数后,自动将套接字设置为非阻塞模式。而应用程序中调用select()函数后,并不能改变套接字的工作方式

  • 下面,开始介绍一下WSAAsyncSelect 的函数原型与具体使用方法:
  • int WSAAsyncSelect(

    __in SOCKET s,

  • __in HWND hWnd,

  • __in unsigned int wMsg,

  • __in long lEvent );

  • ● s 参数指定的是我们感兴趣的那个套接字。

  • ● hWnd 参数指定一个窗口句柄,它对应于网络事件发生之后,想要收到通知消息的那个窗口。

  • ● wMsg 参数指定在发生网络事件时,打算接收的消息。该消息会投递到由hWnd窗口句柄指定的那个窗口。(通常,应用程序需要将这个消息设为比Windows的WM_USER大的一个值,避免网络窗口消息与系统预定义的标准窗口消息发生混淆与冲突)

  • ● lEvent 参数指定一个位掩码,对应于一系列网络事件的组合,大多数应用程序通常感兴趣的网络事件类型包括: FD_READ、FD_WRITE、FD_ACCEPT、FD_CONNECT、FD_CLOSE。当然,到底使用FD_ACCEPT,还是使用FD_CONNECT类型,要取决于应用程序的身份是客户端,还是服务器。如应用程序同时对多个网络事件有兴趣,只需对各种类型执行一次简单的按位OR(或)运算,然后将它们分配给lEvent就可以了,例如: WSAAsyncSeltct(s, hwnd, WM_SOCKET, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE);

  • 解释说明:我们的应用程序以后便可在套接字s上,接收到有关连接、发送、接收以及套接字关闭这一系列网络事件的通知。

  • FD_READ 应用程序想要接收有关是否可读的通知,以便读入数据

  • FD_WRITE 应用程序想要接收有关是否可写的通知,以便写入数据

  • FD_ACCEPT 应用程序想接收与进入连接有关的通知

  • FD_CONNECT 应用程序想接收与一次连接完成的通知

  • FD_CLOSE 应用程序想接收与套接字关闭的通知

  •   需要注意的地方
  • 注意①: 多个事件务必在套接字上一次注册! 另外还要注意的是,一旦在某个套接字上允许了事件通知,那么以后除非明确调用closesocket命令,或者由应用程序针对那个套接字调用了WSAAsyncSelect,从而更改了注册的网络事件类型,否则的话,事件通知会永远有效!若将lEvent参数设为0,效果相当于停止在套接字上进行的所有网络事件通知。
  • 注意 ②: 若应用程序针对一个套接字调用了WSAAsyncSelect,那么套接字的模式会从“锁定”变成“非锁定”。这样一来,如果调用了像WSARecv这样的Winsock函数,但当时却并没有数据可用,那么必然会造成调用的失败,并返回WSAEWOULDBLOCK错误。为防止这一点,应用程序应依赖于由WSAAsyncSelect的uMsg参数指定的用户自定义窗口消息,来判断网络事件类型何时在套接字上发生;而不应盲目地进行调用。
  • 注意 ③:应用程序如何对 FD_WRITE 事件通知进行处理。 只有在三种条件下,才会发出 FD_WRITE 通知: ■ 使用 connect 或 WSAConnect,一个套接字首次建立了连接。 ■ 使用 accept 或 WSAAccept,套接字被接受以后。 ■ 若 send、WSASend、sendto 或 WSASendTo 操作失败,返回WSAEWOULDBLOCK 错误,而且缓冲区的空间变得可用。 因此,作为一个应用程序,自收到首条 FD_WRITE 消息开始,便应认为自己必然能在一个套接字上发出数据,直至一个send、WSASend、sendto 或 WSASendTo 返回套接字错误 WSAEWOULDBLOCK。经过了这样的失败以后,要再用另一条 FD_WRITE 通知应用程序再次发送数据。
  • 应用程序在一个套接字上成功调用了WSAAsyncSelect之后,会在与hWnd窗口句柄对应的窗口例程中,以Windows消息的形式,接收网络事件通知。
  • 窗口例程通常定义如下:
  • LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg,
  • WPARAM wParam,
  • LPARAM lParam );
  • ● hWnd 参数指定一个窗口的句柄,对窗口例程的调用正是由那个窗口发出的。
  • ● uMsg 参数指定需要对哪些消息进行处理。这里我们感兴趣的是WSAAsyncSelect调用中定义的消息。
  • ● wParam 参数指定在其上面发生了一个网络事件的套接字。假若同时为这个窗口例程分配了多个套接字,这个参数的重要性便显示出来了。
  • ● lParam参数中,包含了两方面重要的信息。其中, lParam的低字(低位字)指定了已经发生的网络事件,而lParam的高字(高位字)包含了可能出现的任何错误代码。
  • 步骤:网络事件消息抵达一个窗口例程后,应用程序首先应检查lParam的高字位,以判断是否在网络错误。 这里有一个特殊的宏: WSAGETSELECTERROR,可用它返回高字位包含的错误信息。 若应用程序发现套接字上没有产生任何错误,接着便应调查到底是哪个网络事件类型,具体的做法便是读取lParam低字位的内容。 此时可使用另一个特殊的宏:WSAGETSELECTEVENT,用它返回lParam的低字部分。
  • 总结一下,WSAAsyncSelect模型的优势和不足:
  • 优势: 1.该模型的使用方便了在基于消息的Windows环境下开发套接字的应用程序。开发人员可以像处理其他消息一样对网络事件消息进行处理。
  • 2.该模型确保接收所有数据提供了很好的机制。通过注册FD_CLOSE网络事件,从容关闭服务器与客户端的连接保证了数据全部接收。
  • 不足: 1.该模型局限在,他基于Windows的消息机制,必须在应用程序中创建窗口。当然,在开发中可以根据具体情况是否显示该窗口。MFC的CSocketWnd类就是用来创建一个不显示的窗口,并在该类中声明接收网络事件消息处理函数。
  • 2.由于调用WSAAsyncSelect()函数后,自动将套接字设置为非阻塞状态。当应用程序为接收到网络事件调用相应函数时,未必能够成功返回。这无疑增加了开发人员使用该模型的难度。对于这一点可以从MFC CSocket类的Accept()、Receive()和Send()函数的实现得到验证。

最新文章

  1. 1627. Join
  2. jquery的全选插件
  3. 将Vim改造为强大的IDE—Vim集成Ctags/Taglist/Cscope/Winmanager/NERDTree/OmniCppComplete(有图有真相)(转)
  4. 2.7---判断链表是否是回文(CC150)
  5. Runtime.getRuntime().exec()
  6. grunt压缩合并代码
  7. Android 手机卫士15--程序锁
  8. HDU 4396
  9. 小课堂Week12 Clean Code Part1
  10. ios开发——面试篇(一)
  11. poj1753解题报告(枚举、组合数)
  12. mac磁盘满解决方案
  13. hdu 1575 Tr A(矩阵高速电源输入)
  14. Ubuntu部署可视化爬虫Portia2.0环境以及入门
  15. Python全栈问答小技巧_1
  16. 关于Unity中NGUI的Pivot和锚点
  17. Servlet----------通过 GenericServlet 开发Servlet
  18. python3操作sqlserver,查询数据统计导出csv
  19. Hibernate 查询sql结果行数的几种方法
  20. HDU 5936 Difference(折半搜索(中途相遇法))

热门文章

  1. openstack-ocata-仪表盘服务6
  2. linux memcached Session共享
  3. R语言︱缺失值处理之多重插补——mice包
  4. 【mongodb系统学习之十一】mongodb删除数据
  5. Excel 2010高级应用-柱形图(一)
  6. PL/SQL集合 ----- varrays
  7. Linux显示内存统计最大和最小的详情
  8. Linux显示进程状态
  9. 使用 pprof 和 Flame-Graph 调试 Golang 应用
  10. OpenStack_I版 3.glance部署