1重叠模型的优点
1可以运行在支持Winsock2的所有Windows平台,而不像完成端口只支持NT系统
2比起阻塞,select,WSAAsyncSelect以及WSAEventSelect等模型,重叠I/O(Overlapped I/O)模型使应用程序能达到更加系统性能
因为他和其他4种模型不同的是,使用重叠模型的应用程序通知缓冲区收发系统直接使用数据,也就是说,如果应用程序
投递了一个10kb大小的缓冲区来接收数据,而数据已经到达套接字,则将该数据直接拷贝到投递的缓冲区,
而4种模型中,数据达到并拷贝到单套接字接收缓冲区,此时应用程序会被告知可以读入的容量,当应用程序调用
接收函数之后,数据才从单套接字缓冲区拷贝应用程序到缓冲区,差别就体现了。
2重叠模型的基本原理
重叠模型是让应用程序使用重叠数据结构(WSAOVERLAPPED),一次投递一个或多个Winsock I/O请求,针对这些提交的
请求,在他们完成之后,应用程序会收到通知,于是就可通过自己的代码来处理这些数据了。
使用事件通知的方法来实现重叠IO模型,基于事件的话,就要求将Win事件与WSAOVERLAPPED结构关联在一起,
使用重叠结构,常用的send,sendto,recv,recvform也被WSASend,WSARecv等替换掉,
OVERLAPPER SOCKET(重叠Socket)上进行重叠发送的操作,(简单的理解就是异步send,recv)
他们的参数中都有一个Overlapped参数,就是说所有的重叠Socket都要绑定到这个重叠结构体上,
提交一个请求,其他的事情就交给重叠结构去操心, 而其中重叠结构要与Windows事件绑定在一起,
在样,我们调用完WSARecv后.等重叠操作完成,就会有对应的事件来同意我们操作完成,
2重叠模型的基础知识
typedef struct _OVERLAPPED { ULONG_PTR Internal; ULONG_PTR InternalHigh; union { struct { DWORD Offset; DWORD OffsetHigh; } DUMMYSTRUCTNAME; PVOID Pointer; } DUMMYUNIONNAME; HANDLE hEvent; //我们只要关注这个参数, 用来关联事件的 } OVERLAPPED, *LPOVERLAPPED;
2WSARecv系列函数
在重叠模型中,接收数据就要靠他了,他的参数也比recv多定义是这样的:
int WSArecv( SOCKET s, //投递这个操作的套接字 LPWSABUF lpBuffer,//接收缓冲区,与Recv函数不同 LPDWORD lpNumberOfBytesRecvd,//如果接收操作立即完成,这里会返回函数调用 LPDWORD lpFlags, //默认为0 LPWSAOVERLAPPER lpOverlapper,//绑定的重叠结构 LPWSAOVERLAPPER_COMPLETION_ROUTINE lpCompletionRoutine //一个回调 ); 返回值: WSA_IO_PENDING:常见返回值,说明WSARecv操作成功,但是I/O材质没完成,所以需要绑定一个事件来通知
3WSAWaitForMultipleEvents函数
等待某个事件触发的函数,我们需要事件通知我们完成重叠操作,所以需要用到这个参数。
这个函数只能有WSA_MAXIMUM_WAIT_EVENTS对象定义的一个最大值,是64,就是他只能等待64个事件
如果决的小了,就要创建额外的线程,或线程池。
DWORD WSAWaitForMultipleEvents( DWORD cEvents, // 等候事件的总数量 const WSAEVENT* lphEvents, // 事件数组的指针 BOOL fWaitAll, // 如果设置为TRUE则事件中所有的事件被传信才返回,FALSE是当有事件立即返回 DWORD dwTimeout, // 超时时间,如果超时,函数会返回 WSA_WAIT_TIMEOUT // 如果设置为0,函数会立即返回 // 如果设置为 WSA_INFINITE只有在某一个事件被传信后才会返回 BOOL fAlertable ) // 默认用FALSE 返回值: WSA_WAIT_TIMEOUT :最常见的返回值,我们需要做的就是继续等待 WSA_WAIT_FAILED : 出现了错误,请检查cEvents和lphEvents两个参数是否有效
4WSAGetOverlappedResult函数
既然通过WSAWaitForMultipleEvents函数来得到重叠操作的结果,那我们也需要一个函数来查询
一下重叠操作的结果, 这个函数不需要关注返回值
BOOL WSAGetOverlappedResult( SOCKET s, // SOCKET,不用说了 LPWSAOVERLAPPED lpOverlapped, // 这里是我们想要查询结果的那个重叠结构的指针 LPDWORD lpcbTransfer, // 本次重叠操作的实际接收(或发送)的字节数 BOOL fWait, // 设置为TRUE,除非重叠操作完成,否则函数不会返回 // 设置FALSE,而且操作仍处于挂起状态,那么函数就会返回FALSE LPDWORD lpdwFlags // 指向DWORD的指针,负责接收结果标志 第二个参数是输出的 第三个参数也是输出的,就是你接收的字节数 为0那说明对方关闭socket了