在Netty中使用TCP keep-alive来确定客户端是否断开连接

17

我正在尝试确定客户端是否从netty关闭了套接字连接。有没有办法做到这一点?

4个回答

27

通常情况下,当客户端通过close()关闭套接字并且TCP关闭握手成功完成时,将触发channelInactive()(或3中的channelClosed())事件。

然而,在异常情况下,例如客户端机器由于停电或拔掉局域网电缆而离线,可能需要很长时间才能发现连接实际上已经断开。为了检测这种情况,您必须定期向客户端发送一些消息,并期望在特定时间内收到其响应。就像ping一样 - 您应该在协议中定义定期的ping和pong消息,实际上什么都不做,只是检查连接的健康状况。

另外,您可以启用SO_KEEPALIVE,但此选项的keepalive间隔通常取决于操作系统,并且我不推荐使用它。

为了帮助用户相对容易地实现这种行为,Netty提供了ReadTimeoutHandler。配置您的管道,以使ReadTimeoutHandler在一段时间内没有入站流量时引发异常,并在您的exceptionCaught()处理程序方法中关闭连接。如果您是应该发送定期ping消息的一方,请使用定时器(或IdleStateHandler)发送它。


0

这取决于您在netty之上使用的协议。如果您设计它支持类似ping的消息,那么可以简单地发送这些消息。除此之外,netty只是TCP周围一个相当薄的包装。

另请参见this SO post,其中描述了isOpen()及其相关内容。但是,这并不能解决保持活动状态的问题。


那个链接中的答案大多不正确。在SO上有更好的答案。 - user207421
@EJP你有链接吗?如果你能提出修改建议,我会非常乐意接受! - Uli Köhler
我的理解是tcp已经内置了keep-alive。难道不能利用它吗? - Josh Wilson
是的,TCP保持活动状态默认情况下是禁用的,您只需在建立连接后打开它即可。 - Remy Lebeau
我建议您链接到这个答案 - user207421

0
如果您正在编写服务器,而netty是您的客户端,则您的服务器可以通过调用select()或等效方法来检测断开连接,并然后调用recv()来检测。如果recv()返回0,则表示客户端已正常关闭套接字。如果recv()返回-1,则检查errno或等效项以获取实际错误(除了少数情况外,大多数错误都应视为不正常的断开连接)。意外断开连接的问题在于,操作系统可能需要很长时间才能检测到它们,因此您必须启用TCP keep-alives,或要求客户端定期向服务器发送数据。如果一段时间内未从客户端收到任何内容,则假定客户端已经离线并关闭连接的一端。如果客户端希望,可以重新连接。

我认为你误读了问题。他似乎在服务器中使用Netty。 - user207421

0

如果你从已被对等方关闭的连接中读取,你将会得到一些结束流的指示,这依赖于API。如果你向这样的连接写入,你将会得到一个IOException:“连接重置”的错误。TCP没有提供任何其他方式来检测关闭的连接。

TCP keep-alive(a)默认关闭,并且(b)在启用时每两个小时才运行一次。这可能不是你想要的。如果你使用它并且在它检测到连接已经断开之后进行读取或写入,你就会得到上面的重置错误。


在Windows 2000及更高版本中,您可以使用WSAIoctl(SIO_KEEPALIVE_VALS)在每个连接上以编程方式设置所需的TCP保持活动间隔。 - Remy Lebeau

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