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了