C++ 从IOCP线程调用WSAGetLastError()将返回不正确的结果
我调用了C++ 从IOCP线程调用WSAGetLastError()将返回不正确的结果,c++,sockets,iocp,C++,Sockets,Iocp,我调用了WSARecv(),它返回了WSA\u IO\u PENDING。然后我从另一端发送了一个RST数据包。另一个线程中存在的GetQueuedCompletionStatus()函数按预期返回了FALSE,但当我调用WSAGetLastError()时,我得到的是64,而不是WSAECONNRESET 那么为什么WSAGetLastError()没有返回WSAECONNRESET 编辑: 我忘了提到,当我在失败的WSARecv()之后直接调用WSAGetLastError()(因为收到了
WSARecv()
,它返回了WSA\u IO\u PENDING
。然后我从另一端发送了一个RST
数据包。另一个线程中存在的GetQueuedCompletionStatus()
函数按预期返回了FALSE
,但当我调用WSAGetLastError()
时,我得到的是64
,而不是WSAECONNRESET
那么为什么WSAGetLastError()
没有返回WSAECONNRESET
编辑: 我忘了提到,当我在失败的
WSARecv()
之后直接调用WSAGetLastError()
(因为收到了RST
数据包),返回的错误代码是WSAECONNRESET
,而不是64
因此,返回的错误代码似乎取决于调用后是直接失败还是稍后检索完成数据包时失败。这是IOCP的一般问题,您正在对TCP/IP驱动程序堆栈进行低级调用。与Windows中的所有驱动程序一样,它会使用NTSTATUS错误代码报告故障。此处的预期错误是状态\连接\重置 这些本机错误代码需要转换为winapi错误代码。此转换通常是上下文敏感的,它取决于winapi库发出的驱动程序命令。换句话说,如果是Winsock库进行了转换,则只能返回WSAECONNRESET错误。但您的程序中并没有发生这种情况,是GetQueuedCompletionStatus()处理了错误 这是一个通用的帮助函数,用于处理任何设备驱动程序的IOCP。没有上下文,重叠结构几乎不足以指示I/O请求是如何启动的。转到,它记录了从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()无法将已删除的错误映射回WSA特定的错误。GetQueuedCompletionStatus()设置线程的“最后一个错误”代码时,NTSTATUS代码丢失。所以它没有,它只是返回它能返回的
您所期望的是一个wsagetqueedcompletionstatus()函数,因此可以使用Winsock规则正确地进行此错误转换。没有。这些天来,我更喜欢使用关于如何正确编写Windows代码的最终权威,即.NET Framework源代码,可从。我已链接到SocketAsyncEventArgs.CompletionCallback()方法的源。其中包含密钥:
// 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()获取正确的返回值。这不是很直观:)64是
ERROR\u NETNAME\u DELETED
。这就是它的工作方式。你必须处理它。根据我使用WinSock IOCP的经验,它通常会报告ERROR\u NETNAME\u DELETED
,而不是WSAECONNRESET
,因此只需将这两个错误视为相同来处理。@Remy Lebeau将报告WSAGetLastError()返回的所有错误代码
IOCP线程内部可能会错误\u网络名\u被删除
或只是WSAECONNRESET
?并非所有错误,但我不知道哪些错误会具体映射到错误\u网络名\u被删除
。我总是把它看作是一种意外的分离。它是否真的是由RST
引起的重要问题?这不是一种优雅的断开方式。@Remy Lebeau在我的情况下,这并不重要,但是知道断开的原因在其他情况下可能很重要。