我正在尝试确定客户端是否从netty关闭了套接字连接。有没有办法做到这一点?
通常情况下,当客户端通过close()
关闭套接字并且TCP关闭握手成功完成时,将触发channelInactive()
(或3中的channelClosed()
)事件。
然而,在异常情况下,例如客户端机器由于停电或拔掉局域网电缆而离线,可能需要很长时间才能发现连接实际上已经断开。为了检测这种情况,您必须定期向客户端发送一些消息,并期望在特定时间内收到其响应。就像ping一样 - 您应该在协议中定义定期的ping和pong消息,实际上什么都不做,只是检查连接的健康状况。
另外,您可以启用SO_KEEPALIVE
,但此选项的keepalive间隔通常取决于操作系统,并且我不推荐使用它。
为了帮助用户相对容易地实现这种行为,Netty提供了ReadTimeoutHandler
。配置您的管道,以使ReadTimeoutHandler
在一段时间内没有入站流量时引发异常,并在您的exceptionCaught()
处理程序方法中关闭连接。如果您是应该发送定期ping消息的一方,请使用定时器(或IdleStateHandler
)发送它。
这取决于您在netty之上使用的协议。如果您设计它支持类似ping的消息,那么可以简单地发送这些消息。除此之外,netty只是TCP周围一个相当薄的包装。
另请参见this SO post,其中描述了isOpen()
及其相关内容。但是,这并不能解决保持活动状态的问题。
select()
或等效方法来检测断开连接,并然后调用recv()
来检测。如果recv()
返回0,则表示客户端已正常关闭套接字。如果recv()
返回-1,则检查errno
或等效项以获取实际错误(除了少数情况外,大多数错误都应视为不正常的断开连接)。意外断开连接的问题在于,操作系统可能需要很长时间才能检测到它们,因此您必须启用TCP keep-alives,或要求客户端定期向服务器发送数据。如果一段时间内未从客户端收到任何内容,则假定客户端已经离线并关闭连接的一端。如果客户端希望,可以重新连接。如果你从已被对等方关闭的连接中读取,你将会得到一些结束流的指示,这依赖于API。如果你向这样的连接写入,你将会得到一个IOException:“连接重置”的错误。TCP没有提供任何其他方式来检测关闭的连接。
TCP keep-alive(a)默认关闭,并且(b)在启用时每两个小时才运行一次。这可能不是你想要的。如果你使用它并且在它检测到连接已经断开之后进行读取或写入,你就会得到上面的重置错误。
WSAIoctl(SIO_KEEPALIVE_VALS)
在每个连接上以编程方式设置所需的TCP保持活动间隔。 - Remy Lebeau