Это общая проблема с IOCP, вы делаете низкоуровневый вызов стека драйверов TCP/IP. Которые, как и все драйверы в Windows, сообщают о сбое с кодами ошибок NTSTATUS. Здесь ожидается ошибка STATUS_CONNECTION_RESET.
Эти собственные коды ошибок необходимо преобразовать в код ошибки winapi. Этот перевод обычно зависит от контекста, это зависит от того, какая библиотека winapi выдала команду драйвера. Другими словами, вы можете вернуть ошибку WSAECONNRESET только в том случае, если это была библиотека Winsock, которая выполнила перевод. Но это не то, что произошло в вашей программе, это была GetQueuedCompletionStatus(), которая обработала ошибку.
Это общая вспомогательная функция, которая обрабатывает IOCP для любого драйвера устройства. Здесь нет контекста, структуры OVERLAPPED недостаточно, чтобы указать, как был запущен запрос ввода-вывода. Перейдите к этой статье базы знаний, в ней описано сопоставление по умолчанию кодов ошибок 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, код NTSTATUS был потерян, когда GetQueuedCompletionStatus() установил код "последней ошибки" для потока. Так что это не так, он просто возвращает то, что может.
Что вы ожидаете, так это функцию WSAGetQueuedCompletionStatus(), чтобы этот перевод ошибок мог происходить правильно, используя правила 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(). Это не очень интуитивно :)
person
Community
schedule
10.03.2015
ERROR_NETNAME_DELETED
. Именно так это и работает. Вам придется иметь дело с этим. По моему опыту использования WinSock IOCP, он обычно сообщаетERROR_NETNAME_DELETED
, а неWSAECONNRESET
, поэтому просто обрабатывайте обе ошибки, как если бы они были одинаковыми. - person Remy Lebeau   schedule 08.03.2015WSAGetLastError()
внутри потока IOCP, бытьERROR_NETNAME_DELETED
или простоWSAECONNRESET
? - person Tom   schedule 08.03.2015ERROR_NETNAME_DELETED
. Я всегда отношусь к этому как к неожиданному разрыву связи. Действительно ли имеет значение, было ли это вызваноRST
или нет? Это не изящное отключение в ту или иную сторону. - person Remy Lebeau   schedule 08.03.2015