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

时间:2017-02-23 16:26:46

标签: c sockets winapi winsock iocp

假设我有两个程序,一个客户端和一个服务器,并且我在同一台计算机上运行客户端和服务器(因此速度非常快),并且说客户端套接字的接收缓冲区为空,并且服务器不会向客户端发送任何数据,除非客户端告诉服务器这样做。

现在在客户端,我致电WSASend(),之后致电WSARecv()

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

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

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

  • 第一个完成包是WSASend()(告诉我数据 已被放置在客户端套接字的发送缓冲区中。

  • 第二个完成包是WSARecv()(告诉我数据 已被放置在我传递给WSARecv()的缓冲区中 叫它)。

现在我的问题是:WSARecv()的完成数据包是否可能在WSASend()的完成数据包之前放入完成端口(所以当我调用GetQueuedCompletionStatus()时,我会得到首先是WSARecv()的完成包?

1 个答案:

答案 0 :(得分:2)

你绝不能假设你得到任何完成包的顺序。你必须独立于这个知识 - 这是操作完成。

您必须定义从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);
  ...
}