2015-03-08 8 views
8

Ho chiamato WSARecv() che ha restituito WSA_IO_PENDING. Ho quindi inviato un pacchetto RST dall'altra parte. La funzione GetQueuedCompletionStatus() che esiste in un'altra discussione ha restituito FALSE come previsto, ma quando ho chiamato WSAGetLastError() ho ottenuto 64 anziché WSAECONNRESET.Chiamare WSAGetLastError() da un risultato restituito da un thread IOCP risultato errato

Quindi, perché WSAGetLastError() non è stato restituito WSAECONNRESET?


Edit:

Ho dimenticato di dire che quando chiamo WSAGetLastError() direttamente dopo una mancanza di WSARecv() (a causa di un RST pacchetto in fase di ricezione), il codice di errore restituito è WSAECONNRESET e non 64.

Quindi sembra che il codice di errore restituito dipenda dal fatto che WSARecv() abbia avuto esito negativo direttamente dopo averlo chiamato, oppure abbia avuto esito negativo in seguito durante il recupero di un pacchetto di completamento.

+1

64 è 'ERROR_NETNAME_DELETED'. Questo è solo il modo in cui funziona. Dovrai affrontarlo. Nella mia esperienza di utilizzo di WinSock IOCP, di solito viene segnalato "ERROR_NETNAME_DELETED" e non "WSAECONNRESET", quindi gestisci entrambi gli errori come se fossero gli stessi. –

+0

@Remy Lebeau Tutti i codici di errore restituiti da 'WSAGetLastError()' all'interno di un thread IOCP saranno 'ERROR_NETNAME_DELETED' o solo' WSAECONNRESET'? – Tom

+0

Non tutti gli errori, ma non so quali si mappano specificamente a 'ERROR_NETNAME_DELETED'. Lo tratto sempre come una disconnessione inaspettata. Ha davvero importanza se fosse causato da un 'RST' o no? Non è una disconnessione elegante in un modo o nell'altro. –

risposta

12

Questo è un problema generico con IOCP, si sta effettuando una chiamata di basso livello allo stack di driver TCP/IP. Quale, come tutti i driver fanno in Windows, segnala l'errore con i codici di errore di NTSTATUS. L'errore previsto qui è STATUS_CONNECTION_RESET.

Questi codici di errore nativi devono essere convertiti in un codice di errore winapi. Questa traduzione è normalmente sensibile al contesto, dipende da quale libreria winapi ha emesso il comando driver. In altre parole, è possibile ottenere sempre un errore WSAECONNRESET solo se era la libreria Winsock a eseguire la traduzione. Ma non è quello che è successo nel tuo programma, è stato GetQueuedCompletionStatus() che ha gestito l'errore.

Che è una funzione di supporto generica che gestisce IOCP per qualsiasi driver di periferica. Non esiste un contesto, la struttura OVERLAPPED non è sufficiente per indicare come è iniziata la richiesta di I/O. Vai a this KB article, documenta la mappatura di default dai codici di errore NTSTATUS ai codici di errore di winapi. La mappatura utilizzata da GetQueuedCompletionStatus(). Le voci rilevanti nella lista sono:

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 

Queste erano, ehm, non scelte fantastiche. Probabilmente torna ai primissimi Windows, quando Lanman era il livello di rete preferito. WSAGetLastError() è abbastanza impotente per associare ERROR_NETNAME_DELETED a un errore specifico WSA, il codice NTSTATUS è stato perso quando GetQueuedCompletionStatus() ha impostato il codice "ultimo errore" per il thread. Quindi non lo fa, restituisce solo quello che può.


quello che ci si aspetta è una funzione WSAGetQueuedCompletionStatus() in modo da questa traduzione errore può accadere in modo corretto, utilizzando le regole Winsock. Non ce n'è uno. In questi giorni preferisco usare l'autorità finale su come scrivere correttamente il codice di Windows, l'origine di .NET Framework come disponibile dallo Reference Source. Ho collegato il codice sorgente al metodo SocketAsyncEventArgs.CompletionCallback(). Che contiene la chiave:

// 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(); 

O in altre parole, è necessario fare un ulteriore chiamata a WSAGetOverlappedResult() per ottenere il valore di ritorno adeguato da GetLastError().Questo non è molto intuitivo :)

Problemi correlati