2024年6月11日发(作者:)
在Winsock中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于之前的选择模型,
异步选择模型和事件选择模型。重叠模型的基本设计原理便是让应用程序使用一个重叠的数据结构
(WSAOVERLAPPED),一次投递一个或多个 Winsock I/O 请求。针对这些提交的请求,在它
们完成之后,我们的应用程序会收到通知,于是我们就可以对数据进行处理了。
使用重叠I/O模型必须使用 WSA_FLAG_OVERLAPPED 这个标志,创建一个套接字。例如:
1 SOCKET s = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
如果使用socket这个函数的话,会默认自动使用WSA_FLAG_OVERLAPPED。
创建好套接字后,将其与本地接口绑定到一起之后便可以开始重叠I/O操作了。不过需要注意的时,
在重叠I/O的状态下不能使用send、recv等函数,他们被WSASend、WSARecv函数替换掉了。
基本上都是以WSA开头的Winsock函数,主要有一下几种:
WSASend
WSASendTo
WSARecv
WSARecvFrom
WSAloctl
AcceptEx
TrnasmitFile
使用时还要指定一个WSAOVERLAPPED结构(可选)。
通常情况下,调用这些函数会返回WSA_IO_PENDING,这就说明函数调用成功了,但是I/O函
数还没完成。
当调用这些函数的时候,如果指定了WSAOVERLAPPED参数,函数完成后会立即返回,无论套接
字是否为阻塞模式,可以通过等待时间对象通知或者通过完成例程来得知I/O请求是否成功。通常
情况下第一种时间通知的方法比较常用。
这里只需要注意一点,重叠函数(如:WSARecv)的参数中都有一个 Overlapped 参数,我们可以
假设是把我们的WSARecv这样的操作“绑定”到这个重叠结构上,提交一个请求,而不是将操作立
即完成,其他的事情就交给重叠结构去做,而其中重叠结构又要与Windows的事件对象“绑定”在一
起,这样我们调用完 WSARecv 以后就可以“坐享其成”,等到重叠操作完成以后,自然会有与之对
应的事件来通知我们操作完成,然后我们就可以来根据重叠操作的结果取得我们想要的数据了。
重叠I/O的事件通知方法要求将Win32事件对象和WSAOVERLAPPED结构关联在一起。I/O操
作完成后,事件的状态就会变为已传信。
下面是WSAOVERLAPPED结构体的定义:
1
2
3
4
5
typedef struct _WSAOVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
防爆摄像机厂家/,龙岗厂房出租/
6
7
8
9
10
11
DWORD Offset;
DWORD OffsetHigh;
}; PVOID Pointer;
};
HANDLE hEvent;
} WSAOVERLAPPED, *LPWSAOVERLAPPED;
Internal, InternalHigh, Offset, OffsetHigh为系统内部使用,通常情况下不作修改。
hEvent则需要传递一个事件句柄。可用 WSACreateEvent 函数来创建一个事件对象句柄。一旦创
建好一个事件句柄,简单地将重叠结构的 hEvent 字段分配给事件句柄,再使用重叠结构,调用一
个Winsock函数即可,比如 WSASend 或 WSARecv。
一个重叠 I/O 请求最终完成后,我们的应用程序要负责取回重叠 I/O 操作的结果。一个重叠请求
操作最终完成之后,在事件通知方法中,Winsock会更改与一个 WSAOVERLAPPED 结构对应的
一个事件对象的事件传信状态,将其从“未传信”变成“已传信”。由于一个事件对象已分配给
WSAOVERLAPPED 结构,所以只需简单地调用 WSAWaitForMultipleEvents 函数,
从而判断出一个重叠 I/O 调用在什么时候完成。
发现一次重叠请求完成之后,需要调用WSAGetOverlappedResult函数来判断那个重叠调用到底是
成功还是失败了。该函数定义如下:
1
2
3
4
5
6
7
BOOL WSAAPI WSAGetOverlappedResult(
__in SOCKET s,
__in LPWSAOVERLAPPED lpOverlapped,
__out LPDWORD lpcbTransfer,
__in BOOL fWait,
__out LPDWORD lpdwFlags
);
s对应的就是套接字。lpOverlapped参数指定一个WSAOVERLAPPED结构。lpcbTransfer参数负
责接收一次重叠发送或接收操作实际传输的字节数。fWait 参数用于决定函数是否应该等待一次待
决(未决)的重叠操作完成。若将 fWait设为 TRUE,那么除非操作完成,否则函数不会返回。
若设为FALSE,而且操作仍然处于“待决”状态,那么WSAGetOverlappedResult 函数会返回 FALSE
值,同时返回一个WSAIOINCOMPLETE(I/O操作未完成)错误。但就我们目前的情况来说,由
于需要等候重叠操作的一个已传信事件完成,所以该参数无论采用什么设置,都没有任何效果。
参数 lpdwFlags 对应于一个指针,指向一个DWORD(双字),负责接收结果标志(假如原先的
重叠调用是用WSARecv或WSARecvFrom函数发出的)。
关于这个函数的返回值,一旦调用成功,则会返回TRUE,并且lpcbTransfer会更新。若失败则会
返回FALSE。失败的原因有这么几种:
重叠I/O操作仍在“待决”状态。
重叠I/O操作已经完成,但是存在错误。
重叠操作的完成状态不可判决,因为在WSAGetOverlappedResult函数的参数中存在错误
失败后,lpcbTransfer值不会更新,此时可以调用WSAGetLastError函数。
防爆摄像机厂家/,龙岗厂房出租/


发布评论