Trong phần mềm máy chủ web của riêng tôi, tôi nhận được các mục trong Event Viewer trên máy chủ có chứa stack trace sau:Điều gì gây ra một NullReferenceException trong .NET Threading/chấp nhận kết nối TCP?
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*)
Không cần phải nói, này bị treo quá trình, có nghĩa là máy chủ đi xuống.
Vì không có stacktrace nào đề cập đến mã của riêng tôi, tôi khá bối rối. Đây có phải là lỗi trong .NET không? Nếu vậy, có cách giải quyết nào không? Hoặc là có một nguyên nhân được biết đến với ngoại lệ đặc biệt này?
Tên CompletionPortCallback
được đề cập trong ngăn xếp dẫn tôi tin rằng nó xảy ra khi máy chủ cố gắng chấp nhận kết nối TCP đến, vì vậy tôi sẽ bao gồm mã có liên quan cho điều đó bên dưới. Tất nhiên tôi rất vui khi bao gồm mã khác nếu bạn cho rằng vấn đề nằm ở nơi khác.
Các cuộc gọi đến BeginAccept
trông như thế này:
Ở đây, _listeningSocket
là loại System.Net.Sockets.Socket
.
Phương thức acceptSocket
được hiển thị bên dưới. Tôi sẽ giả định rằng các ý kiến giải thích mã cũng đủ; nếu không, tôi vui lòng làm rõ trong một bình luận. Vì mã này chạy trong chế độ RELEASE trên máy chủ trực tiếp, tất nhiên, #if DEBUG
sẽ là sai.
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
}
Theo như tôi biết bạn nên vượt qua '_listeningSocket' trong lệnh' BeginAccept() 'thay vì null:' _listeningSocket.BeginAccept (acceptSocket, _listeningSocket); 'xem tài liệu và ví dụ. Đó là lý do tại sao bạn nhận được ngoại lệ ArgumentNull. –
Đây rõ ràng là một lỗi trong khuôn khổ .NET. Nếu bạn đã msiused API lỗi sẽ xảy ra ngay sau đó, không sâu trong ruột của BCL trên một cuộc gọi lại IO. Câu hỏi bây giờ là làm thế nào để làm việc xung quanh nó. – usr