我打开一个TCP套接字并将其连接到网络上的另一个套接字。然后我可以成功地发送和接收数据。我设置了一个定时器,每秒钟向套接字发送一些内容。
然后我粗暴地中断了连接,强制失去连接(在这种情况下是拔掉以太网电缆)。我的套接字仍然报告每秒钟成功写出数据。这种情况持续了大约1小时30分钟,最终会产生一个写入错误。
什么确定了套接字最终认为另一端已经消失的超时时间?是操作系统(Ubuntu 11.04),还是来自TCP/IP规范,或者是一个套接字配置选项?
我打开一个TCP套接字并将其连接到网络上的另一个套接字。然后我可以成功地发送和接收数据。我设置了一个定时器,每秒钟向套接字发送一些内容。
然后我粗暴地中断了连接,强制失去连接(在这种情况下是拔掉以太网电缆)。我的套接字仍然报告每秒钟成功写出数据。这种情况持续了大约1小时30分钟,最终会产生一个写入错误。
什么确定了套接字最终认为另一端已经消失的超时时间?是操作系统(Ubuntu 11.04),还是来自TCP/IP规范,或者是一个套接字配置选项?
拔掉网络电缆不会断开TCP连接(1),但会中断通信。当重新插上电缆并建立IP连接后,所有的后向数据都将传输。这就是TCP可靠性的体现,即使在蜂窝网络上也是如此。
TCP发送数据时,期望收到一个ACK响应。如果一定时间内没有收到ACK响应,TCP会重新发送数据并等待。TCP等待时间通常呈指数级增长。
若经过多次重传或总共等待时间过长仍未收到ACK响应,TCP将认为连接已经"断开"。具体重传次数或等待时间取决于你的操作系统及其配置,但通常超时时间为几分钟左右。
来自Linux的tcp.7手册页:
tcp_retries2 (integer; default: 15; since Linux 2.2)
The maximum number of times a TCP packet is retransmitted in
established state before giving up. The default value is 15, which
corresponds to a duration of approximately between 13 to 30 minutes,
depending on the retransmission timeout. The RFC 1122 specified
minimum limit of 100 seconds is typically deemed too short.
更改检测连接是否消失所需时间的值通常是您希望调整的值。
(1) 这有例外情况。当操作系统注意到电缆被拔出时,它可能会通知上层所有连接都应被视为“中断”。
TCP_USER_TIMEOUT(自Linux 2.6.37起)此选项以unsigned int作为参数。当该值大于0时,它指定在毫秒中传输的数据在未被确认之前可以保留的最长时间,在此期间TCP将强制关闭相应的连接并返回ETIMEDOUT给应用程序。如果将选项值指定为0,则TCP将使用系统默认值。
这里有两个优秀的答案:这里 和 这里。
TCP用户超时可能适用于您的情况:TCP用户超时控制在连接被强制关闭之前,传输的数据可以保持未确认的时间长度。
有3个依赖于操作系统的TCP超时参数。
在Linux上,默认值为:
tcp_keepalive_time 默认7200秒
tcp_keepalive_probes 默认9
tcp_keepalive_intvl 默认75秒
总超时时间是tcp_keepalive_time + (tcp_keepalive_probes * tcp_keepalive_intvl),使用这些默认值 7200 + (9 * 75) = 7875 秒
在Linux上设置这些参数:
sysctl -w net.ipv4.tcp_keepalive_time=1800 net.ipv4.tcp_keepalive_probes=3 net.ipv4.tcp_keepalive_intvl=20