TCP套接字连接

5
我有一个Windows服务,其中包括使用.NET System.Net.Sockets库监听来自远程设备的传入数据。下面的示例仅每60秒推送一次数据的远程设备。
偶尔,此服务将停止,并且服务器的Windows日志中会出现以下消息。
The process was terminated due to an unhandled exception. 
   Exception Info: System.Net.Sockets.SocketException Stack: 
   at System.Net.Sockets.Socket.EndReceive(System.IAsyncResult) 
   at Uk.Co.RCID.MoteServer.Server.SocketListener.ReceiveCallback(System.IAsyncResult) 
   at System.Net.LazyAsyncResult.Complete(IntPtr)
   at System.Net.ContextAwareResult.CompleteCallback(System.Object) 
   at System.Threading.ExecutionContext.runTryCode(System.Object) 
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object) 
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) 
   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*)  

将此事件的时间与我的最后一条日志记录匹配后,我发现当远程设备在较短的时间内两次连接服务时(通常每60秒连接一次以推送数据),会出现致命异常。以下是系统崩溃前的最后一条日志记录。

2011-05-20 13:39:19,545 [6] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Waiting for a connection...
2011-05-20 13:39:19,545 [10] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Connection established on [10.64.128.60:11000]
2011-05-20 13:40:20,982 [6] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Waiting for a connection...
2011-05-20 13:40:20,982 [5] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Connection established on [10.64.128.60:11000]

不想公开源代码(如果需要,我可以安排,但需要删除某些详细信息),socket监听代码基于此示例。

http://msdn.microsoft.com/en-us/library/5w7b7x5f.aspx

非常感谢您的帮助。


大家好,

谢谢你们的回应。

我在ReceiveCallback函数中添加了更多的日志记录和异常处理,并在今天早上在我的日志文件中发现了以下内容...

2011-05-25 04:52:26,816 [5] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - Waiting for a connection...
2011-05-25 04:52:26,816 [10] INFO  Uk.Co.RCID.MoteServer.Server.SocketListener     [(null)] - Connection established on [10.64.128.60:11000]
2011-05-25 04:53:26,841 [10] WARN  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - SocketException thrown in ReceiveCallback
2011-05-25 04:53:26,841 [10] WARN  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - ErrorCode: [10054]
2011-05-25 04:53:26,841 [10] WARN  Uk.Co.RCID.MoteServer.Server.SocketListener [(null)] - System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult) at Uk.Co.RCID.MoteServer.Server.SocketListener.ReceiveCallback(IAsyncResult ar)

所以,关键是(正如上面一些答案中强调的那样)在ReceiveCallback函数内捕获异常,并决定它们是否严重到足以使你的应用程序崩溃。


你捕获的异常的 InnerException 属性中是否有内部异常?我认为在你从套接字接收数据的代码中可能会抛出一些异常。 - Nick
很不幸,我没有这个信息。因为出错情况不经常发生,所以需要更多记录来重新创建问题,这需要一些时间。我将尝试使用模拟的远程设备重新创建它。 - user767428
4个回答

2

如果你的代码与示例非常接近,那么你应该在 ReceiveCallback 函数中围绕以下内容添加一个 try-catch:

int read = handler.EndReceive(ar);

因为它可能只是简单的情况,比如在你尝试接收时套接字连接关闭了。

与其结束进程,你可以尝试继续执行。


这个建议似乎是可行的,因为远程设备是一个嵌入式电子设备,很可能在此期间关闭连接。谢谢。 - user767428

2

在所有回调方法中,您应该始终catch(Exception err)务必记录异常信息。

原因是,在除主线程之外的任何其他线程中抛出未处理的异常都会终止您的应用程序。

您应将套接字回调中的任何异常视为客户端已断开连接。当然,您可能会遇到致命的异常,例如OutOfMemoryException,这些异常应终止应用程序。但在大多数情况下,这种情况是不太可能发生的。


0

我会做的第一件事是检查抛出的SocketExceptionErrorCode属性的值。在winsock错误代码列表中查找此值,以获取可能出错的指针。

如果您发布错误代码,则我可能能够提供进一步帮助。


谢谢迄今为止提供的建议。我将添加更多日志记录以检索到目前为止所请求的信息。 - user767428

0

当客户端连接无法从半开放状态转换为完全开放状态时,EndAccept 可能会抛出异常。此外,请注意,在侦听器关闭后它将抛出 ObjectDisposedException,因此您必须实际查看异常并根据出现的问题做出决定。

EndReceive 通常在客户端连接被强制关闭时抛出异常,但同样需要查看异常并根据所抛出的异常做出决定。


我在 ReceiveCallback 函数中增加了更多的日志记录,并在昨晚的日志文件中发现了以下内容... - user767428

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接