2013-09-05 12 views
6

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 
} 
+0

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. –

+0

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

Odpowiedz

-1

Myślę, że ten wyjątek jest zgłaszany, ponieważ przekazujesz referencję zerową jako drugi parametr.

Od MSDN Dokumentacji Socket.BeginAccept (http://msdn.microsoft.com/de-de/library/5bb431f9.aspx):

należy utworzyć metody wywołania zwrotnego, która implementuje delegata AsyncCallback i przekazać swoją nazwę metody BeginAccept. Aby to zrobić, musisz przekazać obiekt Socket nasłuchujący do BeginAccept przez parametr state. Jeśli Twój callback potrzebuje więcej informacji, możesz utworzyć małą klasę, aby pomieścić Socket i inne wymagane informacje. Przekaż instancję tej klasy do metody BeginAccept za pomocą parametru state.

+0

To nie jest to. W ogóle nie zależy mu na parametrze * state *. Po prostu przechowuje je niezmienione w obiekcie 'IAsyncResult', gdzie można go odzyskać w wywołaniu zwrotnym. Może mieć wartość "null" i to zawsze działa dla mnie. – Timwi

4

Odpowiedź jest równie prosta jak rozczarowująca.

Okazuje się, że ArgumentNullException rzeczywiście rzucony przez mojego własnego kodu, który wykonany w zwrotnego do wywołania asynchronicznego i powinny zostały w ślad stosu. Ufałem, że ślad stosu jest zbyt duży; fakt, że to nie pokazało się w śladzie stosu, przez długi czas prowadziło mnie na niewłaściwym torze.

Jak dowiadują się deweloperzy C#, instrukcja throw; (nie throw e;) powinna zachować niezmieniony ślad stosu wyjątku. System.Net.FixedSizeReader.ReadCallback przechwytuje i wyrzuca wyjątek za pomocą takiego oświadczenia throw;, ale ślad stosu pokazany w Podglądzie zdarzeń został obcięty. Mogę tylko domyślać się, że jest to błąd w CLR lub przeglądarce zdarzeń lub w pewnej interakcji między tymi dwoma, powodując jedynie wyświetlenie części śledzenia stosu z instrukcji throw;.

Po uruchomieniu oprogramowania na konsoli zamiast w usłudze, o której powinienem był pomyśleć znacznie wcześniej, na konsoli pojawił się pełny ślad wyjątku, wskazując, że prawdziwą przyczyną wyjątku był mój własny kod.

+0

dziękuję za odpowiedź na własne pytanie, sugestia, że ​​stacktrace został obcięty i uruchomienie go jako konsoli pomógł mi bardzo. W moim przypadku oczekiwałem, że mój WebException.response zostanie wypełniony tam, gdzie go nie było -> nullreference -> wyrzucił moją usługę nservicebus z wody bez żadnego błędu –

0

Na podstawie https://connect.microsoft.com/VisualStudio/feedback/details/535917 i moich własnych doświadczeń, jest to prawdopodobnie wyjątek domina z innego wcześniejszego wydania.

Spróbuj dodać globalną procedurę obsługi wyjątku i zaloguj się & opróżnij wszystkie wyjątki na dysku, a następnie sprawdź plik dziennika po awarii, aby znaleźć prawdziwą przyczynę.

Powiązane problemy