C# SocketAsyncEventArgs 和网络故障
Posted
技术标签:
【中文标题】C# SocketAsyncEventArgs 和网络故障【英文标题】:C# SocketAsyncEventArgs and network glitches 【发布时间】:2014-09-03 13:34:26 【问题描述】:我已经以规范的方式使用 SAEA 实现了异步套接字:
-
为操作准备好一个 SAEA 池,保留引用,这样 GC 就不必移动内存
操作完成后更换 SAEA。
我发现了一个与网络中断有关的问题。具体来说,sendAsync 完成 在发生中断时不会触发事件,因此我的池不会被重新填充。这最终会导致程序崩溃,因为无论池的大小如何,它都会用完 SAEA。
你如何避免这种情况?您不能简单地保留对旧 SAEA 的引用,因为这会给您一个异常,说明它已经在等待操作。
我正在寻找一种优雅地替换 SAEA 的方法。数据不被传输不是问题。一种可能的方法是在等待一定数量的对象时在套接字上运行关闭。有没有人有这方面的经验?
【问题讨论】:
那会是什么类型的中断?在大多数错误情况下,完成确实会发生相关的错误信息。是断线问题吗? 是的,您可以通过拔下电缆来模拟它,但可能无法通过关闭网络端口来模拟。目前还发生了另一起海底电缆断裂事件,而且似乎经常发生。 【参考方案1】:在基本上无限网络延迟的情况下(就像电缆被切断的情况一样),确实可能没有发布完成。
从此类问题中恢复的唯一方法是实施某种版本的心跳方案。 SO_KEEPALIVE 选项存在于套接字上,但默认行为通常不是您想要的。来自 MSDN:
对于 TCP,默认保活超时为 2 小时,保活间隔为 1 秒。
我建议实施您自己的心跳方案,如果在合理的时间内没有收到响应心跳,则认为连接“死”。例如,您可以:
-
定期发送“心跳”(或在没有其他消息发送时)
记下接收到heartbeats(或任何)消息的时间,并设置一个超时时间,这样如果触发了超时,那么您没有收到数据太久,应该关闭并重新启动连接
【讨论】:
【参考方案2】:建议的解决方案确实有效。只需在每次发送之前检查是否超过了某个限制,如果是,则关闭+关闭套接字。这可以防止对象泄漏,允许稍后优雅地重新连接。
我通过拔下电缆并反复重新连接来测试这一点。在旧情况下,池将清空。现在它在网络中断中幸存下来。
【讨论】:
以上是关于C# SocketAsyncEventArgs 和网络故障的主要内容,如果未能解决你的问题,请参考以下文章
C#高性能大容量SOCKET并发:SocketAsyncEventArgs封装
C# SocketAsyncEventArgs 停止触发完成事件
SocketAsyncEventArgs 和缓冲,而消息是在部分