Dies ist ein generisches Problem mit IOCP, Sie führen einen Low-Level-Aufruf an den TCP/IP-Treiberstapel. Welche, wie alle Treiber in Windows tun, melden Fehler mit NTSTATUS-Fehlercodes. Der erwartete Fehler ist hier STATUS_CONNECTION_RESET.
Diese systemeigenen Fehlercodes müssen in einen winapi-Fehlercode übersetzt werden. Diese Übersetzung ist normalerweise kontextsensitiv, es hängt davon ab, welche winapi-Bibliothek den Treiberbefehl ausgegeben hat. Mit anderen Worten, Sie können einen WSAECONNRESET-Fehler immer nur dann zurückerhalten, wenn die Winsock-Bibliothek die Übersetzung ausgeführt hat. Aber das ist nicht in Ihrem Programm passiert, es war GetQueuedCompletionStatus(), das den Fehler behandelte.
Welche ist eine generische Hilfsfunktion, die IOCP für jeden Gerätetreiber behandelt. Es gibt keinen Kontext, die OVERLAPPED-Struktur ist nicht annähernd genug, um anzuzeigen, wie die I/O-Anforderung gestartet wurde. Wechseln Sie zu this KB article, dokumentiert es die Standardzuordnung von NTSTATUS-Fehlercodes zu Winapi-Fehlercodes. Die Zuordnung, die GetQueuedCompletionStatus() verwendet. Relevante Einträge in der Liste sind:
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
Diese waren, ahem, nicht fantastische Wahlen. Geht wahrscheinlich auf sehr früh Windows zurück, als Lanman die Netzwerkschicht der Wahl war. WSAGetLastError() ist ziemlich machtlos, ERROR_NETNAME_DELETED einem WSA-spezifischen Fehler zuzuordnen, der NTSTATUS-Code ging verloren, wenn GetQueuedCompletionStatus() den "letzten Fehler" -Code für den Thread festlegte. Also nicht, es gibt nur zurück, was es kann.
was man erwarten ist eine WSAGetQueuedCompletionStatus() Funktion so dieser Fehler Übersetzung korrekt passieren, Winsock Regeln. Es gibt keinen. In diesen Tagen verwende ich lieber die ultimative Autorität, wie man Windows-Code richtig schreibt, die .NET Framework-Quelle, wie sie von Reference Source verfügbar ist. Ich bin mit der Quelle für die SocketAsyncEventArgs.CompletionCallback() -Methode verbunden. Die den Schlüssel enthält:
// 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();
Oder mit anderen Worten, müssen Sie einen zusätzlichen Aufruf WSAGetOverlappedResult() machen den richtigen Rückgabewert von GetLastError() zu erhalten.Das ist nicht sehr intuitiv :)
64 ist 'ERROR_NETNAME_DELETED'. So funktioniert es. Du wirst damit umgehen müssen. Nach meiner Erfahrung mit WinSock IOCP wird normalerweise 'ERROR_NETNAME_DELETED' und nicht' WSAECONNRESET' gemeldet, also behandeln Sie beide Fehler so, als wären sie gleich. –
@Remy Lebeau Werden alle von 'WSAGetLastError()' in einem IOCP-Thread zurückgegebenen Fehlercodes 'ERROR_NETNAME_DELETED' oder nur' WSAECONNRESET' sein? – Tom
Nicht alle Fehler, aber ich weiß nicht, welche speziell auf 'ERROR_NETNAME_DELETED' abbilden. Ich behandle es immer als eine unerwartete Trennung. Ist es wirklich wichtig, ob es durch eine 'RST' verursacht wurde oder nicht? Es ist nicht ein anmutiges trennt die eine oder andere. –