【发布时间】:2015-12-21 20:59:51
【问题描述】:
我通过切断多个客户端的 Internet 连接来测试模拟断开多个客户端的连接。我发现 TIdTCPServer 没有释放他们的线程,它没有检测到他们的断开连接。相比之下,当我手动关闭客户端时,服务器检测到断开连接并释放其线程。
【问题讨论】:
标签: delphi delphi-2010 indy10
我通过切断多个客户端的 Internet 连接来测试模拟断开多个客户端的连接。我发现 TIdTCPServer 没有释放他们的线程,它没有检测到他们的断开连接。相比之下,当我手动关闭客户端时,服务器检测到断开连接并释放其线程。
【问题讨论】:
标签: delphi delphi-2010 indy10
操作系统未及时检测到异常断开连接。丢失的套接字连接在内部超时可能需要相当长的时间,因此操作系统可以使其无效。在操作系统这样做之前,Indy 无法知道客户端连接已经消失。
为此,您应该:
在应用层数据协议中实现超时。如果您希望客户端向您的服务器发送某些内容,并且它在一定时间内没有这样做,请假设客户端已离开并关闭连接。在空闲活动期间,要求客户端定期向您的服务器发送心跳命令以保持其连接处于活动状态。您可以使用AContext.Connection.IOHandler.CheckForDataOnSource() 方法等待数据到达,也可以使用AContext.Binding.SetSockOpt() 方法指定SO_RCVTIMEO 阻塞读取超时。
如果您无法更改数据协议,您至少可以在套接字本身上启用 TCP 级别的 keep-alives。在服务器的OnConnect事件中,可以调用AContext.Binding.SetKeepAliveValues()方法开启keep-alives。然后操作系统将为您处理保持活动状态,如果超时,则将使连接失效。
话虽如此,还要确保您的服务器事件处理程序没有吞下 Indy 异常(源自 EIdException)。这也可能导致服务器无法正确终止线程,如果连接丢失并且 Indy 引发有关它的异常但您不允许服务器处理它。如果您需要捕获异常(用于日志记录等),请确保重新引发任何EIdException 派生的异常并让服务器处理它。
【讨论】: