C++ Windows Socket五种I/O模型之WSAEventSelect模型
WSAEventSelect模型
WSAEventSelect 模型是 Windows socekts 提供的另一个有用异步 IO 模型,与 select 模型相比较,WSAAsyncSelect 与 WSAEventSelect 模型都是被动接受的。网络事件发生时,系统通知应用程序。而 select 模型是主动的,应用程序主动调用 select 函数来检查是否发生了网络事件。
WSAEventSelect函数
int WSAEventSelect(SOCKET s, WSAEVENT hEvent, Long lNetworkEvents);
// s 为套接字句柄。
// hEvent 为事件对象句柄。
// lNetworkEvents 为应用程序感兴趣的网络事件集合。
备注:返回值成功返回 0,失败返回 SOCKET_ERROR, 可以调用WSAGetLastError() 获取具体错误码。如果调用该函数之后,套接字自动设置为非阻塞模式。
WSACreateEvent()函数
应用程序在调用 WSAEventSelect 函数之前,必须先创建一个事件对象。创建的方法是调用WSACreateEvent 函数:
WSAEVENT WSACreateEvent(void);
返回值:调用成功则返回事件对象句柄。否则返回 WSA_INVALID_EVENT。返回的事件对象的初始态为未触发态手工重置的对象。
WSACloseEvent()函数
不再使用事件对象时要将其关闭。这可以调用WSACloseEvent函数:
bool WSACloseEvent(WSAEVENT hEvent);
返回值:调用成功返回TRUE,否则false。
WSAWaitForMultipleEvents()
函数可以等待网络事件的发生。它的目的是等待一个或是所有的事件对象变为已触发状态:
DWORD WSAWaitForMultipleEvents(
DWORD cEvents,
const WSAEVENT *plhEvent,
BOOL fWaitAll,
DWORD dwTimeOUT,
BOOL fAlertable);
备注:
cEvents:为事件对象句柄个数。至少为1,最多为 WSA_MAXIMUM_WAIT_EVENTS,64个。
lphEvents为指向对象句柄数组指针。
fWaitAll:如果为TRUE,则该函数在所有事件对象都转变为已触发时才返回。如为false,只要有一个对象被触发,函数即返回。
dwTimeOUT:函数阻塞事件。单位为毫秒。在时间用完后函数会返回。如果为 WSA_INFINITE 则函数会一直等待下去。如果超时返回,函数返回 WSA_WAIT_TIMEOUT。
fAlterable:该参数说明当完成例程在系统队列中排队等待执行时,该函数是否返回。这主要应用于重叠IO模型,以后还会介绍。此处将其设置为 false 即可。
另外:
- 当 bWaitAll 为 TRUE 时:
如果返回值为WSA_TIMEOUT则表明等待超时。
WSA_EVENT_0表明所有对象都已变成触发态。等待成功。
WAIT_IO_COMPLETION说明一个或多个完成例程已经排队等待执行。 - 如果 bWaitAll 为 false 时:
WSA_WAIT_EVENT_0 到 WSA_WAIT_EVENT_0+cEvent-1 范围内的值,说明有一个对象变为触发态。它在数组中的下标为:返回值-WSA_EVENT_0。
如果函数调用失败,则返回 WSA_WAIT_FAILED。
WSAEnumNetworkEvents()函数
通过 WSAWaitForMultipleEvents 的返回值可以获得发生网络事件的套接字。但是,应用程序需要判断在该套接字上究竟发生了什么网络事件。
int WSAEnumNetworkEvents(SOCKET s, WSAEVENT hEvent, LPWSANETWORKEVENTS lpNetworkEvents);
参数:
s 为发生网络事件的套接字句柄。
hEvent 为被重置的事件对象句柄(可选)。
lpNetworkEvents 为指向 WSANETWORKEVENTS 结构指针。
如果 hEvent 不为 NULL,则该事件被重置。如果为 NULL,需要调用 WSAResetEvent 函数设置事件为非触发状态。
调用成功返回 0,否则为 SOCKETS_ERROR。
以上就是WSAEventSelect 模型所有用到的函数,下面是具体的服务端代码具体代码,其中异常判断没有添加,可以自行添加。
//编译环境 vs2019
#include <WinSock2.h>
#include <iostream>
#include <thread>
#include <fstream>
using namespace std;
#pragma comment