原文连接:
http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html
以下为对原文的阅读笔记
说明:
主动关闭的一方称为local end,被动关闭的一方称为remote end
本地IP、本地端口、远端IP、远端端口这一“四元组”称为quadruplet,也称为socket
1、TIME_WAIT主要是为了解决两个问题:
a.delayed packet:新连接能够丢弃旧连接的延时到达的数据包
b.LAST ACK:确保remote end,在local end发送的ack丢失的情况下,仍能完成关闭,而不是永远处于LAST ACK状态:
如果remote end永远处于LAST ACK,则对于local end新的握手请求,会返回RST;这样,双方就再也建立不起连接了
2、TIME-WAIT带来的问题主要是端口不够用,TIME-WAIT连接占用的内存和CPU其实并不多。如果local end和remote end都可以增加端口、增加IP,那最好不过了
3、如果确实需要“对付”TIME-WAIT,有几种方法:
a.disable socket lingering
原理就是在close时不是走正常的关闭流程,而是直接RST,这样就不会进入TIME-WAIT
但对于non-blocking的进程来说,也有可能进入TIME-WAIT:如果close后剩余数据在超时前能成功发送
b.net.ipv4.tcp_tw_reuse
只对outgoing connection有效
主要原理就是利用TCP的时间戳选项。如果新报文的时间戳比旧报文的大,则重用旧的quadruplet
delayed packet:丢弃过时的报文
LAST ACK:处于LAST ACK状态的remote end,在local end再次发起握手时,重传FIN,然后local end发送RST关闭旧连接,然后再建立新连接。因此,新连接的建立可能会有轻微的延时
c.net.ipv4.tcp_tw_recycle
对incoming and outgoing connections都有效
利用RTT减少处于TIME-WAIT状态的连接的存活时间,也就是,更快的回收quadruplet
delayed packet:同样是丢弃过时的报文。如果TIME-WAIT状态结束了,则表示是新连接了,不丢弃
LAST ACK:处理同net.ipv4.tcp_tw_reuse
这个方法带来的问题就是,NAT可能有多个内网机器,这些机器之间不共享时间戳,因此会导致那些时间戳小的机器无法连接
(不是很理解的是,tcp_tw_reuse和tcp_tw_recycle都是基于时间戳,为什么tcp_tw_recycle会有NAT的问题,而tcp_tw_reuse没有呢)
后面两种方法都需要tcp_timestamps
4、很多时候TIME-WAIT并不是一个问题,而是一个“需要我们深入理解”的朋友