问题说明:主动关闭套接字的一方必须在time_wait等待2MSL。 默认值为2分钟
原因分析:
主动关闭的客户端可以看到,在最后一次TIME_WAIT时,客户端和服务端实际上关闭了套接字。 (在上级APP应用程序中断访问send或recv时抛出socket error。
表示服务端发送FIN时,进行了关闭套接字,进入了LAST_ACK状态。 在此状态下,服务端TCP将检测是否在2TTL(1 (一次)时间内启动了重发机制
客户端对FIN进行ack,此时进入TIME_WAIT,处理服务端可能触发的重发FIN。 (为什么可能,是因为客户端可能进行了ack,服务端由于超时等原因进行了重新发送。 )为了陪你玩,客户端牺牲了2毫秒的时间
如果服务端LAST_ACK的重发次数超过tcp_orphan_retries内核参数的设置次数,则放弃重发,进入关闭状态。
tcp_orphan_retries内核参数的默认值为0
总结:
TIME_WAIT存在的意义主要有两个。
能够维持连接状态,可靠地关闭TCP连接。 如果连接主动闭合发送的最后一个ACK丢失,连接被动闭合将重新发送FIN消息。 因此,主动关闭端必须保持连接状态,以支持在接收到重发的FIN后重发ACK。 如果没有TIME_WAIT,并且丢失了最后一个ACK,则被动关闭侧将暂时保持LAST_ACK,等待重传; 现在,如果活动关闭端立即创建新的TCP连接,并使用相同的四元组,则连接将无法创建,并且端到端重置。
等待网络中此连接的所有旧的重复丢失的消息消失,以防止此类消息干扰新的相同四对TCP连接。 因为这些消息的编号可能正好位于新连接的接收窗口中。
解决方案:实际上,只有在新的TCP连接和旧的TCP连接四对完全匹配,并且旧的迷走消息号在新连接的接收窗口中时,才会引起干扰。 为了使用处于TIME_WAIT状态的端口,目前大多数系统的实现都得到了改进和扩展。
从新连接SYN通知的初始序列号必须大于TIME_WAIT状态下的旧连接的序列号,这在某种程度上确保不与旧连接的消息序列号重叠。
打开TCP timestamps扩展选项后,新连接的时间戳必须大于处于TIME_WAIT状态的旧连接的时间戳,可以确保旧连接的消息不影响新连接。
因此,如果打开了TCP timestamps扩展选项(net.ipv4.tcp_timestamps=1),则可以放心地设置SO_REUSEADDR选项,以支持程序的快速重新启动
请注意不要与net.ipv4.tcp_tw_reuse系统参数混淆。 此参数仅在客户端调用connect创建连接时启用,并且TIME_WAIT状态超过1秒的端口可用。 防止最后一次确认丢失。 另一方面,SO_REUSEADDR在绑定端口上启用。 通常,用于服务端监听时,不仅可以使用TIME_WAIT状态端口,还可以使用本地非LISTEN状态端口。 另一个端口也必须设置SO_REUSEADDR。