据我所知,TCP套接字上的阻塞接收并不总是通过返回-1
值或提高IO来检测连接错误(由于网络故障或远程端点故障)例外:有时它可能会无限期地挂起。
管理此问题的一种方法是为阻止接收设置超时。如果已知接收时间的上限,则可以将此限制设置为超时,并且可以在超时到期时将连接视为丢失;当这样的上限不是先验的时候,例如在连接保持打开以接收发布的pub-sub系统中,要设置的超时有点任意但是它的到期可以触发ping / pong请求来验证连接(以及端点)仍在运行。
我想知道异步接收的使用是否也能解决检测连接失败的问题。在boost :: asio中,我会调用socket::asynch_read_some()
注册一个异步调用的处理程序,而在java.nio中,我会将通道配置为非阻塞,并将其注册到具有OP_READ
兴趣标志的选择器。我认为正确的连接失败检测意味着,在第一种情况下,处理程序将使用非0 error_code调用,而在第二种情况下,选择器将选择错误的通道但后续的read()
开启频道会返回-1
或抛出IOException
。
这种行为是否可以通过异步接收得到保证,或者是否存在连接失败后的情况,例如,在boost :: asio中,处理程序永远不会被调用,或者在java.nio中,选择器永远不会选择通道?< / p>
非常感谢。
答案 0 :(得分:5)
我相信你指的是TCP half-open connection问题(该术语的RFC 793含义)。在这种情况下,接收操作系统永远不会接收丢失连接的指示,因此它永远不会通知应用程序。无论应用程序是同步读取还是异步读取,都不会进入。
当连接的发送方以某种方式不再知道网络连接时,会出现问题。例如,当
时,就会发生这种情况发送操作系统突然终止/重启(断电,操作系统故障/ BSOD等)。
发送方关闭其侧面,同时双方之间存在网络中断并清理其侧面:例如,在中断期间发送操作系统干净地重新启动,传输Windows操作系统已从网络中拔出
当发生这种情况时,接收方可能正在等待数据或永远不会到来的FIN。除非接收方发送消息,否则它无法实现发送方不再知道接收方。
您的解决方案(超时)是解决问题的一种方法,但它应该包括向发送方发送消息。同样,读取是同步的还是异步的,只是它不会读取并无限期地等待数据或FIN。另一种解决方案是使用某些TCP堆栈支持的TCP KEEPALIVE功能。但任何通用解决方案的难点通常是determining a proper timeout,因为超时高度依赖于特定应用程序的特性。
答案 1 :(得分:4)
由于TCP的工作原理,您通常必须发送数据才能发现硬连接失败,以确定不会返回任何ACK
数据包。有些协议试图通过定期使用keep-alive或ping数据包来识别这样的条件:如果一方在X时间内没有收到这样的数据包(也许在尝试并使其自身失败之后),它可以认为连接已经死了。 / p>
要回答你的问题,阻止和非阻塞接收应该执行相同的操作,除了阻止自身的行为,因此两者都会遇到同样的问题。为了确保您可以从远程主机检测到静默故障,您必须使用像我所描述的保持活动形式。