在我自己的网络服务器软件中,我在服务器上的事件查看器中获取包含以下堆栈跟踪的条目:
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*)
毋庸置疑,这会导致进程崩溃,这意味着服务器出现故障。
由于堆栈跟踪都没有提到我自己的代码,所以我很困惑。这是.NET中的错误吗?如果是这样,有没有任何已知的解决方法?或者这个特殊例外有没有已知的原因?
堆栈跟踪中提到的名称CompletionPortCallback
让我相信它是在服务器尝试接受传入的TCP连接时发生的,因此我将在下面包含相关代码。当然,如果您认为问题出在其他地方,我很乐意提供其他代码。
对BeginAccept
的调用如下:
_listeningSocket.BeginAccept(acceptSocket, null);
此处_listeningSocket
的类型为System.Net.Sockets.Socket
。
acceptSocket
方法如下所示。我将假设这些评论很好地解释了代码;如果没有,我很乐意在评论中澄清。由于此代码在实时服务器上以RELEASE模式运行,因此#if DEBUG
当然是假的。
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 :(得分:4)
答案很简单,令人失望。
事实证明ArgumentNullException
确实是由我自己的代码抛出的,它在异步调用的回调中执行,应该在堆栈跟踪中。我太信任堆栈跟踪了;事实上,这没有显示在堆栈轨迹中,这使我在很长一段时间内走错了路。
正如C#开发人员所知,throw;
语句(不是throw e;
)应该保持异常堆栈跟踪不变。 System.Net.FixedSizeReader.ReadCallback
通过这样的throw;
语句捕获并重新抛出异常,但事件查看器中显示的堆栈跟踪被截断。我只能猜测这是CLR或事件查看器中的错误或两者之间的一些交互,导致只显示从throw;
指令开始的堆栈跟踪部分。
当我在控制台而不是服务上运行软件时,我应该更早地想到这一点,在控制台上显示异常的完整堆栈跟踪,表明异常的真正原因是我自己的代码
答案 1 :(得分:0)
基于https://connect.microsoft.com/VisualStudio/feedback/details/535917和我自己的经验,这可能是另一个早期问题的连锁异常。
尝试添加全局异常处理程序和日志&刷新所有磁盘异常,然后在崩溃后检查日志文件以找到真正的原因。
答案 2 :(得分:-1)
我认为抛出此异常是因为您将空引用作为第二个参数传递。
来自MSDN Socket.BeginAccept文档(http://msdn.microsoft.com/de-de/library/5bb431f9.aspx):
您必须创建一个实现AsyncCallback委托的回调方法,并将其名称传递给BeginAccept方法。要做到这一点,至少必须通过state参数将侦听Socket对象传递给BeginAccept。如果您的回调需要更多信息,您可以创建一个小类来保存Socket和其他所需信息。通过state参数将此类的实例传递给BeginAccept方法。