TCP套接字无连接超时

55

我打开一个TCP套接字并将其连接到网络上的另一个套接字。然后我可以成功地发送和接收数据。我设置了一个定时器,每秒钟向套接字发送一些内容。

然后我粗暴地中断了连接,强制失去连接(在这种情况下是拔掉以太网电缆)。我的套接字仍然报告每秒钟成功写出数据。这种情况持续了大约1小时30分钟,最终会产生一个写入错误。

什么确定了套接字最终认为另一端已经消失的超时时间?是操作系统(Ubuntu 11.04),还是来自TCP/IP规范,或者是一个套接字配置选项?


3
或许这个链接可以给你答案。 - SKi
3个回答

81

拔掉网络电缆不会断开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) 这有例外情况。当操作系统注意到电缆被拔出时,它可能会通知上层所有连接都应被视为“中断”。


1
我每天都会发出成千上万的HTTP请求,现在我正在使用Websockets(nodejs)工作,所以自然而然地我想了解更多关于好老的sockets的知识,我现在意识到套接字是如何美妙地工作的。它是可靠的、面向连接的和主机特定的协议,这就是为什么重试次数取决于操作系统的原因! - Karan Kaw
你能否提及一下recv/send缓冲区大小的填充率?如果发送缓冲区填满,应用程序可能会收到I/O错误。 - huch
1
应用程序将不会收到I/O错误。接收方将在其“接收窗口”为空时阻塞或读取零字节,具体取决于读取是同步还是异步的。发送方将在其“发送窗口”(以及任何其他操作系统缓冲区)已满时阻塞或发送零字节,也取决于情况。只有当TCP确定连接被“断开”时,才会发生I/O错误。 - Brian White

1
如果想要快速将套接字错误传播到应用程序代码中,您可能希望尝试此套接字选项:

TCP_USER_TIMEOUT(自Linux 2.6.37起)此选项以unsigned int作为参数。当该值大于0时,它指定在毫秒中传输的数据在未被确认之前可以保留的最长时间,在此期间TCP将强制关闭相应的连接并返回ETIMEDOUT给应用程序。如果将选项值指定为0,则TCP将使用系统默认值。


请参见linux/man/tcp(7)上的完整说明。此选项比tcp_retries2编辑更灵活,并且确切适用于客户端套接字不知道服务器状态并可能进入所谓的半关闭状态的情况。

0

这里有两个优秀的答案:这里这里
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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接