假设我有两个程序,一个客户端和一个服务器,并且我在同一台计算机上运行客户端和服务器(因此速度非常快),并且说客户端套接字的接收缓冲区为空,并且服务器不会向客户端发送任何数据,除非客户端告诉服务器这样做。
现在在客户端,我致电WSASend()
,之后致电WSARecv()
:
WSASend(...); // tell the server to send me some data
WSARecv(...);
因此,在上面的代码中,WSASend()
告诉服务器将一些数据发送到客户端(例如:字符串"hello"
)。
现在一段时间后,两个完成包将被放入完成端口:
第一个完成包是WSASend()
(告诉我数据
已被放置在客户端套接字的发送缓冲区中。
第二个完成包是WSARecv()
(告诉我数据
已被放置在我传递给WSARecv()
的缓冲区中
叫它)。
现在我的问题是:WSARecv()
的完成数据包是否可能在WSASend()
的完成数据包之前放入完成端口(所以当我调用GetQueuedCompletionStatus()
时,我会得到首先是WSARecv()
的完成包?
答案 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);
...
}