我调用了 WSARecv()
,它返回了 WSA_IO_PENDING
。然后我从另一端发送了一个 RST
数据包。存在于另一个线程中的 GetQueuedCompletionStatus()
函数按预期返回了 FALSE
,但是当我调用 WSAGetLastError()
时,我得到了 64
而不是 WSAECONNRESET
。
那么为什么 WSAGetLastError()
没有返回 WSAECONNRESET
?
编辑:
我忘了提到当我在 WSARecv()
失败后直接调用 WSAGetLastError()
时(因为 RST
数据包被接收),返回的错误代码是 WSAECONNRESET
而不是 64
。
所以看起来返回的错误代码取决于 WSARecv()
是在调用它之后直接失败,还是稍后在检索完成数据包时失败。
最佳答案
这是 IOCP 的一般问题,您正在对 TCP/IP 驱动程序堆栈进行低级调用。与 Windows 中的所有驱动程序一样,它会报告带有 NTSTATUS 错误代码的故障。此处的预期错误是 STATUS_CONNECTION_RESET。
这些 native 错误代码需要转换为 winapi 错误代码。此翻译通常上下文相关,它取决于发出驱动程序命令的 winapi 库。换句话说,如果是 Winsock 库进行了翻译,您只能返回 WSAECONNRESET 错误。但这不是您的程序中发生的情况,是 GetQueuedCompletionStatus() 处理了错误。
这是一个通用的辅助函数,可以处理任何设备驱动程序的 IOCP。没有上下文,OVERLAPPED 结构不足以表明 I/O 请求是如何开始的。转this KB article ,它记录了从 NTSTATUS 错误代码到 winapi 错误代码的默认映射。 GetQueuedCompletionStatus() 使用的映射。列表中的相关条目是:
STATUS_NETWORK_NAME_DELETED ERROR_NETNAME_DELETED
STATUS_LOCAL_DISCONNECT ERROR_NETNAME_DELETED
STATUS_REMOTE_DISCONNECT ERROR_NETNAME_DELETED
STATUS_ADDRESS_CLOSED ERROR_NETNAME_DELETED
STATUS_CONNECTION_DISCONNECTED ERROR_NETNAME_DELETED
STATUS_CONNECTION_RESET ERROR_NETNAME_DELETED
咳咳,这些并不是很好的选择。可能可以追溯到非常早期的 Windows,当时 Lanman 是首选的网络层。 WSAGetLastError() 无法将 ERROR_NETNAME_DELETED 映射回 WSA 特定错误,当 GetQueuedCompletionStatus() 为线程设置“最后一个错误”代码时,NTSTATUS 代码丢失。所以它不会,它只是返回它可以返回的内容。
您期望的是一个 WSAGetQueuedCompletionStatus() 函数,因此可以使用 Winsock 规则正确地进行错误转换。没有一个。这些天我更喜欢使用关于如何正确编写 Windows 代码的最终权威,.NET Framework 源代码可从 Reference Source 获得。 .我链接到 SocketAsyncEventArgs.CompletionCallback() 方法的源代码。其中包含 key :
// The Async IO completed with a failure.
// here we need to call WSAGetOverlappedResult() just so Marshal.GetLastWin32Error() will return the correct error.
bool success = UnsafeNclNativeMethods.OSSOCK.WSAGetOverlappedResult(
m_CurrentSocket.SafeHandle,
m_PtrNativeOverlapped,
out numBytes,
false,
out socketFlags);
socketError = (SocketError)Marshal.GetLastWin32Error();
或者换句话说,您必须额外调用 WSAGetOverlappedResult() 才能从 GetLastError() 获得正确的返回值。这不是很直观:)
关于c++ - 从 IOCP 线程调用 WSAGetLastError() 返回不正确的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28925003/