5

在我自己的网络服务器软件中,我在服务器上的事件查看器中获取条目,其中包含以下堆栈跟踪:

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
}
4

3 回答 3

4

答案既简单又令人失望。

事实证明,ArgumentNullException确实是由我自己的代码抛出的,该代码在异步调用的回调中执行,并且应该在堆栈跟踪中。我太相信堆栈跟踪了;这没有在堆栈跟踪中显示的事实导致我在很长一段时间内走错了路。

正如 C# 开发人员所知,throw;语句 (not throw e;) 应该保持异常堆栈跟踪不变。System.Net.FixedSizeReader.ReadCallback通过这样的语句捕获并重新抛出异常throw;,但事件查看器中显示的堆栈跟踪被截断。我只能推测这是 CLR 或事件查看器中的错误或两者之间的一些交互,仅导致从throw;指令开始的堆栈跟踪部分显示。

当我在控制台上运行软件而不是作为服务运行时,我应该更早想到的,异常的完整堆栈跟踪显示在控制台上,表明异常的真正原因是我自己的代码。

于 2013-09-05T19:14:38.037 回答
0

根据https://connect.microsoft.com/VisualStudio/feedback/details/535917和我自己的经验,这可能是另一个早期问题的连锁异常。

尝试添加一个全局异常处理程序并将所有异常记录并刷新到磁盘,然后在崩溃后检查日志文件以找出真正的原因。

于 2014-09-01T13:05:35.487 回答
-1

我认为抛出此异常是因为您将空引用作为第二个参数传递。

从 MSDN Socket.BeginAccept 文档(http://msdn.microsoft.com/de-de/library/5bb431f9.aspx):

您必须创建一个实现 AsyncCallback 委托的回调方法并将其名称传递给 BeginAccept 方法。为此,您至少必须通过 state 参数将侦听的 Socket 对象传递给 BeginAccept。如果您的回调需要更多信息,您可以创建一个小类来保存 Socket 和其他所需信息。通过 state 参数将此类的实例传递给 BeginAccept 方法。

于 2013-09-05T11:32:03.067 回答