当主动关闭连接,收到对端的Fin后,socket会进入到TIME_WAIT状态,用于重传FIN的ACK消息,这个状态会维持2MSL时长。那么此时绑定本地IP:端口,系统会报Address already in use。有两种方法可以允许重新使用处于TIME_WAIT状态的端口:
(1)设置选项SO_REUSEADDR,但是TCP不允许一个新的连接建立在相同的插口对上。
client[bsdi:1098] -----》server[sun:6666],在server侧主动断开连接,则server侧的socket会进入TIME_WAIT状态。使用SO_REUSEADDR选项绑定6666端口成功,connect[bsdi:1099]成功,但是connect[bsdi:1098]失败,这是符合 “TCP不允许一个新的连接建立在相同的插口对上”原则。但是如果sun仍然作为server,绑定并监听6666端口,[bsdi:1098]主动连接[sun:6666]成功!!!
(2)设置内核参数tcp_tw_recycle,快速回收处于TIME_WAIT的socket。但是设置启用tcp_tw_recycle时,需同时打开内核参数tcp_timestamps(一般操作系统默认打开),否则设置tcp_tw_recycle无效。
tcp_timestamps的用途描述:
An additional mechanism could be added to the TCP, a per-host cache of the last timestamp received from any connection. This value could then be used in the PAWS mechanism to reject old duplicate segments from earlier incarnations of the connection, if the timestamp clock can be guaranteed to have ticked at least once since the old connection was open. This would require that the TIME-WAIT delay plus the RTT together must be at least one tick of the sender’s timestamp clock. Such an extension is not part of the proposal of this RFC.
大概意思是说TCP有一种行为,可以缓存每个主机最新的时间戳,后续请求中如果时间戳小于缓存的时间戳,即视为无效,相应的数据包会被丢弃。
由于同一NAT下的不同机器的时间戳不一定保证同步,所以就导致同一个NAT过来的数据包的时间戳不能保证单调递增主机地址都一样,所以在NAT环境中需要慎用tcp_timestamps