在这种情况下,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"
)。
现在一段时间后,两个完成数据包将被放置在完成端口:
第一个完成包是给WSASend()
的(告诉我数据
已被放置在客户端套接字的发送缓冲区中)。
第二个完成数据包是给WSARecv()
的(告诉我数据
已经放在我传递给 WSARecv()
的缓冲区中,当我
叫它)。
现在我的问题是:是否可以将 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);
...
}
说我有两个程序,一个client和一个server,我是运行client和server在同一台电脑上(所以速度极快),说client套接字的接收缓冲区为空,服务器不会向客户端发送任何数据,除非客户端告诉服务器这样做。
现在在客户端中,我调用 WSASend()
然后调用 WSARecv()
:
WSASend(...); // tell the server to send me some data
WSARecv(...);
所以在上面的代码中,WSASend()
告诉服务器向客户端发送一些数据(例如:字符串 "hello"
)。
现在一段时间后,两个完成数据包将被放置在完成端口:
第一个完成包是给
WSASend()
的(告诉我数据 已被放置在客户端套接字的发送缓冲区中)。第二个完成数据包是给
WSARecv()
的(告诉我数据 已经放在我传递给WSARecv()
的缓冲区中,当我 叫它)。
现在我的问题是:是否可以将 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);
...
}