目录
(3)网络事件等待函数WSAWaitForMultipleEvents()
(4)网络事件枚举函数WSAEnumNetworkEvents()
一、异步选择模型
1、基于消息的选择模型
(1)WSAAsyncSelect模型
- 阻塞模型是在不知I/O事件是否发生的情况下,应用程序会按自己既定的流程主动去执行IO操作,结果通常是阻塞并等待相应事件发生;
- 非阻塞模型也是在不知I/O事件是否发生的情况下,应用程序按自己既定的流程,反复执行IO操作直到操作成功(I/O事件发生);
- Select模型则是在不知I/O事件是否发生的情况下,应用程序按既定流程调用select函数主动检查关心的IO事件是否发生,如果没有发生则select()函数也是阻塞等待。
共同特点:不管 I/O事件是否发生,应用程序都会按既定流程主动试着进行I/O操作,而且直至操作成功才会罢休,因此这三种套接字模型都属于同步模型。
尽管非阻塞模型和Select模型一次能够尝试对多个套接字进行I/O操作,要比阻塞模型效率高很多,但应用程序一旦开始I/O操作,则I/O操作完成之前都是无法进行其它操作。
解决这一问题的方法是采用异步I/O模型。
- 异步套接字I/O模型中,当网络I/O事件发生时,系统将采用某种机制通知应用程序,应用程序只有在收到事件通知时才调用相应的套接字函数进行I/O操作。
WSAAsyncSelect模型和WSAEventSelect模型都属于异步I/O模型,二者的差别在于系统通知应用程序的方法不同。
(2) WSAAsyncSelect()函数
WSAAsyncSelect()函数,其格式如下。
WSAAsyncSelect(s, hWnd, 0, 0);
- s为要被取消注册网络事件的套接字,hWnd为注册这些事件时指定的接收网络事件消息的窗口的句柄。
- 取消网络事件的注册之后,系统将不再为该套接字发送任何与网络事件相关的消息。
- 需要特别强调,WSAAsyncSelect模型应用在Windows环境下,使用该模型时必须创建窗口。
- 而Slelect模型广泛应用在Unix系统和Windows系统,使用该模型不需要创建窗口。
应用程序调用WSAAsyncSelect()函数后,自动将套接字设置为非阻塞模式,而应用程序中调用select()函数后,并不能改变该套接字的工作方式。
- WSAAsyncSelect模型是基于Windows的消息机制实现的,当网络事件发生时,Windows系统将发送一条消息给应用程序,应用程序将根据消息做出相应的处理。该模型的核心是WSAAsyncSelect()函数。
- WSAAsyncSelect()函数的主要功能:是为指定的套接字注册一个或多个应用程序需要关注的网络事件。
- WSAAsyncSelect模型是非阻塞的,在应用程序中调用WSAAsyncSelect()函数后,该函数将向系统注册完成参数lEvent指定的网络事件后立即返回。
- WSAAsyncSelet模型是异步的,当已被注册的网络事件发生时,系统将向应用程序发送消息,该消息将由参数hWnd指定的窗口的相应消息处理函数进行处理,编写相应的消息处理函数是程序编写的主要工作之一。
注意:注册网络事件时需要指定事件发生时需要发送的消息以及处理该消息的窗口的句柄。
程序运行时,一旦被注册的事件发生,系统将向指定的窗口发送指定的消息。
int WSAAsyncSelect
{
SOCKET s, //需要事件通知的套接字
HWND hWnd,//当网络事件发生时接收消息的窗口句柄
unsigned int wMsg, //当网络事件发生时向窗口发送的用户自定义消息
long lEvent //要注册的应用程序感兴趣的套接字s的网络事件集合
};
函数返回值:应用程序感兴趣的事件注册成功,则返回0;如果注册失败,则返回SOCKET_ERROR。
常用的网络事件包括FD_READ网络事件、FD_WRITE事件、FD_ACCEPT事件、FD_CONNECT事件、FD_CLOSE事件等。
- FD_READ事件:读数据就绪的通知事件。事件触发时调用recv(), recvfrom(), WSARecv(), WSARecvfrom()。
- FD_WRITE事件:写数据就绪的通知事件。事件触发时调用send(), sendto(), WSASend(), WSASendto()。
- FD_ACCEPT事件:当前有连接请求需要接受。事件触发时调用accept(), WSAAccept()。
- FD_CONNECT事件:调用connect()函数后,建立连接完成。
- FD_CLOSE事件:仅对面向连接套接字有效,收到套接字关闭时触发。
Tips:
在VC++2017不鼓励使用 WSAAsyncSelect()模型,若使用编译器将发出错误警告并停止编译,如果要关闭错误警告继续编译,需要在头文件stdAfx.h中添加如下宏定义:
- #define _WINSOCK_DEPRECATED_NO_WARNINGS
或者在调用该函数的CPP文件头部使用以下预处理命令:
- #pragma warning(disable : 4996)
(3)使用 WSAAsyncSelect模型接收数据的过程
- 调用recv(