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 和缓冲,而消息是在部分

C# IOCP完成端口模型(简单实用高效)

SocketAsyncEventArgs.Completed 在 Windows 8 中不会触发

是否有必要清理 SocketAsyncEventArgs.Completed?