W moim własnym oprogramowaniu serwer, jestem coraz wpisy w Podglądzie zdarzeń na serwerze, które zawierają następujące ślad stosu:Co powoduje wyjątek NullReferenceException w .NET Threading/Accepting TCP connections?
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.ArgumentNullException
Stack:
at System.Net.FixedSizeReader.ReadCallback(System.IAsyncResult)
at System.Net.LazyAsyncResult.Complete(IntPtr)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
at System.Net.ContextAwareResult.Complete(IntPtr)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)
trzeba dodawać, że to wywala proces, co oznacza, że serwer idzie w dół.
Ponieważ żaden z stacktrace nie wspomina o moim własnym kodzie, jestem całkiem zaintrygowany. Czy jest to błąd w .NET? Jeśli tak, czy są jakieś znane rozwiązania? A może jest znana przyczyna tego szczególnego wyjątku?
Wymieniona w stosie nazwa CompletionPortCallback
prowadzi mnie do przekonania, że występuje, gdy serwer próbuje zaakceptować przychodzące połączenie TCP, więc poniżej zamieszczę odpowiedni kod dla tego połączenia. Oczywiście chętnie dołączę inny kod, jeśli uważasz, że problem leży gdzie indziej.
Wezwanie do BeginAccept
wygląda następująco:
Tutaj _listeningSocket
jest typu System.Net.Sockets.Socket
.
Metoda acceptSocket
jest pokazana poniżej. Zakładam, że komentarze wystarczająco dobrze wyjaśniają kod; jeśli nie, z przyjemnością wyjaśnię to w komentarzu. Ponieważ kod ten jest uruchamiany w trybie RELEASE na serwerze Live, numer #if DEBUG
będzie oczywiście fałszywy.
private void acceptSocket(IAsyncResult result)
{
#if DEBUG
// Workaround for bug in .NET 4.0 and 4.5:
// https://connect.microsoft.com/VisualStudio/feedback/details/535917
new Thread(() =>
#endif
{
// Ensure that this callback is really due to a new connection (might be due to listening socket closure)
if (!IsListening)
return;
// Get the socket
Socket socket = null;
try { socket = _listeningSocket.EndAccept(result); }
catch (SocketException) { } // can happen if the remote party has closed the socket while it was waiting for us to accept
catch (ObjectDisposedException) { }
catch (NullReferenceException) { if (_listeningSocket != null) throw; } // can happen if StopListening is called at precisely the "wrong" time
// Schedule the next socket accept
if (_listeningSocket != null)
try { _listeningSocket.BeginAccept(acceptSocket, null); }
catch (NullReferenceException) { if (_listeningSocket != null) throw; } // can happen if StopListening is called at precisely the "wrong" time
// Handle this connection
if (socket != null)
HandleConnection(socket);
}
#if DEBUG
).Start();
#endif
}
Z tego co wiem, powinieneś przekazać '_listeningSocket' w wywołaniu' BeginAccept() 'zamiast null:' _listeningSocket.BeginAccept (acceptSocket, _listeningSocket); zobacz dokumentację i przykłady. Właśnie dlatego otrzymałeś wyjątek ArgumentNull. –
Jest to oczywiście błąd w strukturze .NET. Jeśli masz problem z interfejsem API, błąd wystąpiłby wtedy, a nie głęboko w trzewiach BCL na wywołanie zwrotnym IO. Teraz pytanie brzmi: jak to obejść. – usr