我们有一个.Net应用程序作为服务运行,使用UdpClient在UDP端口上侦听流量。它可以成功运行数天,并建立数千个连接,但有时Windows事件查看器中的此异常会导致服务崩溃:
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Net.Sockets.SocketException
at System.Net.Sockets.Socket.DoBeginReceiveFrom(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.EndPoint, System.Net.SocketAddress, System.Net.Sockets.OverlappedAsyncResult)
at System.Net.Sockets.Socket.BeginReceiveFrom(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.EndPoint ByRef, System.AsyncCallback, System.Object)
at System.Net.Sockets.UdpClient.BeginReceive(System.AsyncCallback, System.Object)
at OurNamespace.OurService.DataReceived(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.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)
我们处理数据接收的代码非常简单和标准:
private void StartListen()
{
if (UdpServer != null)
{
UdpServer.Close();
UdpServer = null;
}
UdpServer = new UdpClient(new IPEndPoint(IPAddress.Any, ListenPort));
UdpServer.BeginReceive(DataReceived, UdpServer);
}
private void DataReceived(IAsyncResult ar)
{
var c = (UdpClient) ar.AsyncState;
try
{
var receivedIpEndPoint = new IPEndPoint(IPAddress.Any, ListenPort);
var receivedBytes = c.EndReceive(ar, ref receivedIpEndPoint);
if (receivedBytes.Any())
Task.Factory.StartNew(() => InternalExecute(receivedBytes, receivedIpEndPoint));
// Restart listening
c.BeginReceive(DataReceived, ar.AsyncState);
}
catch (Exception ex)
{
ex.Log();
StartListen();
}
}
我在网上进行了快速搜索,有很多原因使套接字编程中出现SocketException,但是我找不到与该特定调用堆栈和进程终止有关的任何东西。
只是证明异常处理有效的证明,我们通常还会在不终止进程的情况下将此行记录到异常处理程序中(连接的正常情况被切断,无需担心):
System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.EndReceiveFrom(IAsyncResult asyncResult, EndPoint& endPoint)
at System.Net.Sockets.UdpClient.EndReceive(IAsyncResult asyncResult, IPEndPoint& remoteEP)
at OurNamespace.OurService.DataReceived(IAsyncResult ar)
我的问题确实是在第一个例外的情况下终止了流程。
我对可能发生的事情只有一个假设,但是我不知道如何证明这一点。调用堆栈中提到的“ IOCompletion”使我想起,我们在使用许多套接字的同一台计算机上运行另一个完全独立的进程,并使用ThreadPool.SetMaxThreads()
手动提高了IO完成线程的最大数量。此其他过程永远不会崩溃,并且可以完美运行。我的假设是Windows达到了一定数量的最大已分配资源,并引发了我们无法做的内部异常,这可能吗?