在这种情况下,WSASend() 和 WSARecv() 的完成数据包的顺序是什么?

What is the order of the completion packets for WSASend() and WSARecv() in this case?

说我有两个程序,一个client和一个server,我是运行client和server在同一台电脑上(所以速度极快),说client套接字的接收缓冲区为空,服务器不会向客户端发送任何数据,除非客户端告诉服务器这样做。

现在在客户端中,我调用 WSASend() 然后调用 WSARecv():

WSASend(...);    // tell the server to send me some data
WSARecv(...);

所以在上面的代码中,WSASend() 告诉服务器向客户端发送一些数据(例如:字符串 "hello")。

现在一段时间后,两个完成数据包将被放置在完成端口:

现在我的问题是:是否可以将 WSARecv() 的完成包放在 WSASend() 的完成包之前的完成端口中(所以当我调用 GetQueuedCompletionStatus() 我将首先获得 WSARecv() 的完成数据包)?

你绝不能假定你得到的完成数据包的任何顺序。您必须独立于此知识 - 即操作完成。

你必须定义一些继承自OVERLAPPED的结构,这个结构放置所有与操作相关的数据。包括描述操作类型的标签。所以当你从 IOCP 中提取指向 OVERLAPPED 的指针时,你将它转换为这个结构并且将会知道 - 这是用于 recv 还是 send,连接还是断开.. 例如

class IO_IRP : public OVERLAPPED 
{
  //...
  DWORD m_opCode;// `recv`, `send`, `dsct`, `cnct`

  IO_IRP(DWORD opCode,...) : m_opCode(opCode) {}

    VOID IOCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered)
    {
        // switch (m_opCode)
        m_pObj->IOCompletionRoutine(m_packet, m_opCode, dwErrorCode, dwNumberOfBytesTransfered, Pointer);
        delete this;
    }

    static VOID CALLBACK _IOCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
    {
        static_cast<IO_IRP*>(lpOverlapped)->IOCompletionRoutine(dwErrorCode, dwNumberOfBytesTransfered);
    }

};

// recv
if (IO_IRP* Irp = new IO_IRP('recv', ..))
{
  WSARecv(..., Irp);
  ...
}