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