TIME_WAIT
我们知道,tcp在关闭连接的时候主动关闭方在最后一个ack报文之后还需要等2MSL才能关闭连接。
原因:
- 确保被动关闭方的正常关闭。在没有TIME_WAIT或者TIME_WAIT过短的情况下,如果最后一个ack报文在网络中丢失,被动关闭方可能永远也关闭不了这个tcp连接,但是有了TIME_WAIT状态之后,如果被动关闭方发送fin报文的timeout之后仍然没有收到ack,就会重传fin报文,此时主动关闭方因为还处于TIME_WAIT状态,还没有关闭连接,所以可以回应ack报文。
- 确保本次连接的所有网络包都消失在网络中,防止对之后的有着相同四元组的连接造成干扰。如果本次连接关闭后,又有新建立的具有相同四元组的tcp连接,tcp/ip协议栈是区分不了哪一个报文属于老连接哪一个报文属于新连接的,2MSL足以保证网络中的所有老报文自然在网络中消失。
MSL
MSL, max segment lifetime, 最大报文生存时间
TTL,time to live,记录着该本文还能经过多少跳的路由,每经过一条路由,TTL就会减一,如果为0,则被抛弃
为什么TIME_WAIT是2MSL? 这其实是一个经验之谈,也有不是2MSL的实现,例如RFC规定的MSL是2mins,但是linux实现是30seconds
也就是说,linux的TIME_WAIT默认是1min
TIME_WAIT过长的问题
- 维持这一个连接占用端口
- 维持这一个连接占用资源
跳过TIME_WAIT
linux下有两种方式跳过TIME_WAIT
- net.ipv4.tcp_tw_reuse(连接发起方在调用 connect() 函数时,内核会随机找一个 time_wait 状态超过 1 秒的连接给新的连接复用)
- net.ipv4.tcp_tw_recycle(允许处于 TIME_WAIT 状态的连接被快速回收)
这两个参数默认都是关闭的,启动这两个参数需要先启用net.ipv4.tcp_timestamps
net.ipv4.tcp_timestamps和PAWS 机制
tcp_timestamps 选项开启之后, PAWS 机制会自动开启,
目的:防止 TCP 包中的序列号发生绕回
方法:开启tcp报文首部的时间戳选项,有2个用处:
- 精确计算RTT
- 防止序列号回绕(PAWS)(序列号,32bits,如果到达4G是就会从0开始,有点循环队列的感觉)
net.ipv4.tcp_tw_reuse的问题
- 被动关闭方在最后一个ack丢失的情况下不能正确关闭
- PAWS不会阻止过期的RST报文,也就是说新的连接可能被老连接的延迟的RST报文干扰(历史 RST 报文可能会终止后面相同四元组的连接,因为 PAWS 检查到即使 RST 是过期的,也不会丢弃)
- 只适用于连接发起方, 连接发起方在调用 connect() 函数时,内核会随机找一个 TIME_WAIT 状态超过 1 秒的连接给新的连接复用
net.ipv4.tcp_tw_recycle的问题
- 被动关闭方在最后一个ack丢失的情况下不能正确关闭
- 如果同时开启了 recycle 和 timestamps 选项,则会开启一种称之为「 per-host 的 PAWS 机制」,客户端在NAT的情况下,SYN包可能被丢弃(因为多个客户端在NAT下发送的tcp包具有相同的ip地址,但是tcp_timestamps却不是递增的,因为他们来自不同的客户端,服务端会丢弃不是递增的tcp包)
- 在 Linux 4.12 版本后,直接取消了tcp_tw_recycle 这一参数。