现在的位置: 首页 > 综合 > 正文

WSAAsyncSelect模型详解

2018年04月20日 ⁄ 综合 ⁄ 共 3347字 ⁄ 字号 评论关闭

        首先,我想说明一下,这篇文章是我在阅读《精通Windows Sockets 网络开发——基于Visual C++》(孙海民 编著,人民邮电出版社出版)这本书的时候,基于这本书归纳总结的一些关于网络编程中WSAAsyncSelect模型的知识。个人觉得这是一本很好的关于Windows Sockets 网络编程的书籍,对网络编程感兴趣或者有项目需要参考书的话,这本书是一个不错的选择。特别说明:本文中的大部分内容均摘录自原书,版权归原作者!
转载请注明出处!

        PS:这是本人第一次在CSND上写博客,由于水平有限,还请各位大神批评指正。

        一、WSAAsyncSelect模型介绍

        WSAAsyncSelect模型是Windows Sockets的一个异步I/O模型。应用程序可以用它在一个套接字上接收以Windows消息为基础的网络事件。应用程序创建套接字后,调用WSAAsyncSelect()函数注册感兴趣的网络事件,当事件发生时,windows窗口接收到消息,然后程序就可以对收到的网络事件进行处理。

       Select模型是阻塞的,而WSAAsyncSelect模型是非阻塞的。应用程序在调用recv()函数接收数据之前,调用WSAAsyncSelect()函数注册网络事件。WSAAsyncSelect()函数立即返回,线程继续运行。当系统中数据准备好时,向应用程序发送消息。程序接收到消息后调用recv()函数接收数据。

       二、WSAAsyncSelect()函数

       函数原型:int  WSAAsyncSelect ( SOCKET  s, HWND  hWnd, u_int  wMsg, long  lEvent)

       参数说明:s: 需要事件通知的套接字

                           hWnd:当网络事件发生时接收消息的窗口句柄

                           wMsg:当网络事件发生时窗口收到的消息

                           lEvent:应用程序感兴趣的网络事件集合

       使用说明:当应用程序中调用该函数后,自动将套接字设置为非阻塞模式。通常,应用程序声明的消息要比Windows的WM_USER值大,以避免该消息与Windows预定义的消息发生混淆。

       网络事件的种类和含义如下

         

网络事件类型

种类

含义

FD_READ

欲接收可读的通知

FD_WRITE

欲接收可写的通知

FD_ACCEPT

欲接收等待接受连接的通知

FD_CONNECT

欲接收一次连接或者多点jion操作完成的通知

FD_OOB

欲接收有带外(OOB)数据到达的通知

FD_CLOSE

欲接收套接字关闭的通知

FD_QOS

欲接收套接字服务质量发生变化的通知

FD_GROUP_QOS

欲接收套接字组服务质量发生变化的通知

FD_ROUTING_INTERFACE_CHANGE

欲在指定方向上,与路由接口发生变化的通知

FD_ADDRESS_LIST_CHANGE

欲接收针对套接字的协议族,本地地址列表发生变化的通知

       可根据需要同时注册多个网络事件,这时要把网络事件类型执行按位或(OR)运算,然后将它们分配给LEvent参数。例如:应用程序希望在套接字上接收连接完成、数据可读和套接字关闭的网络事件,则调用如下函数:

       WSAAsyncSelect ( s,  hwnd,   WM_SOCKET,  FD_CONNECT | FD_READ | FD_CLOSE);

       当该套接字连接完成、有数据可读或者套接字关闭的网络事件发生时,就会有WM_SOCKET消息发送给窗口句柄为hwnd的窗口。

        三、调用WSAAsyncSelect()函数需要注意的问题

        1.接收不到网络事件

        第一种情况是由于在同一个套接字同一个自定义消息上,多次调用WSAAsyncSelect()函数注册不同的网络事件,最后一次函数调用取消了前面注册的网络事件。

        如:WSAAsyncSelect ( s,  hwnd,   WM_SOCKET,  FD_READ);

               WSAAsyncSelect ( s,  hwnd,   WM_SOCKET,  FD_WRITE);

        此时应用程序只能接收到FD_WRITE网络事件。

        如果要取消所有的网络事件通知,告知windows sockets实现不再为该套接字发送任何网络事件相关的消息,要以参数lEvent值为0调用函数,即WSAAsyncSelect ( s,  hwnd,   0,  0)。尽管应用程序调用上述函数取消了网络事件通知,但是在应用程序消息队列中,可能还有网络消息在排队。所以调用上述函数取消网络事件消息后,应用程序还应该继续准备接收网络事件。

        第二种情况是在同一个套接字上,多次调用WSAAsyncSelect()函数,为不同网络事件定义了不同的消息,最后一次该函数调用将取消前面注册的网络事件。

         如:WSAAsyncSelect ( s,  hwnd,   wMsg1,  FD_READ);

                WSAAsyncSelect ( s,  hwnd,   wMsg2,  FD_WRITE);

         第二次函数调用将会取消第一次函数调用的作用,只有FD_WRITE网络事件通过wMsg2通知到窗口。

         2. accept()函数

         因为调用accept()函数接受的套接字和监听套接字具有同样的属性,所以任何为监听套接字设置的网络事件对接受的套接字同样起作用。如果一个监听套接字请求FD_READ和FD_WRITE网络事件,则在该监听套接字上接受的任何套接字也会请求FD_READ和FD_WRITE网络事件,以及发送同样的消息。

        3.关于FD_READ网络事件

        不要为一个FD_READ网络事件多次调用recv()函数。如果为一个FD_READ网络事件调用了多个recv()函数,会使得该应用程序接收到多个FD_READ网络事件。

         如果在一次接收FD_READ网络事件时需要调用多次recv()函数,应用程序应该在调用recv()函数之前关闭FD_READ消息。

        4.如何判断套接字已经关闭

        要使用FD_CLOSE网络事件来判断套接字是否已经关闭。

        接收FD_CLOSE网络事件时,错误代码指示出套接字是从容关闭还是硬关闭。如果错误代码为0,则为从容关闭;若错误代码为WSAECONNRESET,则套接字是硬关闭。

        5.发送数据失败

        一个应用程序当接收到第一个FD_WRITE网络事件后,便认为在该套接字上可以发送数据。当调用输出函数发送数据时,会收到WSAEWOULDBLOCKE错误。经过这样的失败后,要在下一次接收到FD_WRITE网络事件后,再次发送数据,才能够将数据成功发送。

       四、WSAAsyncSelect模型的优缺点

       1.优点

       该模型的使用方便了在基于消息的Windows环境下开发套接字应用程序。开发人员可以像处理其他消息一样对网络事件消息进行处理。该模型为确保接收所有数据提供了很好的机制,通过注册FD_CLOSE网络事件,从容关闭服务器与客户端的连接,保证了数据的全部接收。

      2.缺点

      该模型的局限在于它基于Windows的消息机制,必须在应用程序中创建窗口。当然,在开发中可以根据具体情况确定是否显示该窗口。

      由于调用WSAAsyncSelect()函数后,自动将套接字设置为非阻塞状态。当应用程序为接收到网络事件调用相应的函数时,未必能够成功返回。这无疑增加了开发人员使用该模型的难度。对于这一点,可以从MFC CSocket类的accept()、receive()、和send()函数的实现中得到验证。

 

抱歉!评论已关闭.