TIME_WAIT状态解读
版本:0.01
突然想梳理一下TIME_WAIT
,毕竟自己遇到它好多次了。经常一块出现的问题:too many open file
,当然,这个问题本身跟TIME_WAIT
状态没啥必然的关系。
截取一下官方对TIME_WAIT
的描述:
The socket connection has been closed by the local application, the remote peer has closed its half of the connection, and the system is waiting to be sure that the remote peer received the last acknowledgement.
time_wait status
time_wait
作为HTTP
连接关闭的一个正常状态。当系统time_wait
过多,超过操作系统设定的文件套接字上限时,就会导致整个服务不可用。
唯一确定连接的4个组成部分,它们是客户端及服务端的IP
和PORT
。一般来说,处于time_wait
状态的port
在2mls
内是无法被重复使用的。所以瞬间的wait_wait
过多,直接导致整个系统无法服务。
关闭连接包含4次握手,TCP
是全双工的,有一端需要主动提出关闭。相应的,对端来被动来关闭。对于我们常见的CS
模式,主动和被动的角色是没有明确界限的。
active close
端的系统中才会出现time_wait
的状态。拿请求https://google.com
来举例,客户端在创建连接时,其实并不关心连接的端口号,它是系统随机创建的。google
服务存在一个443
端口,一直处于listen
状态。当客户端断开连接时,客户端系统其实就会出现time_wait
。当服务端主动断开连接时,客户端会出现close_wait
状态。
2MLS
time_wait
也被称为2MLS wait
。全名maximum segment lifetime
, 表示一个数据块在被丢弃之前,在网络中能存在的最长时间。TCP
的数据包是作为IP
数据传输的,而IP
数据包是否有效受限于设置的TTL
,所以该MSL
存在上限。
- 在
2MLS
内,该连接不会处理那些迟到的请求,占用的端口号也无法被系统的其他程序使用。 - 在
TCP
连接中,ACK
消息本身是不安全,因为peer
不需要对ACK
回复ACK
。所以,2MLS
保证了当被动关闭的一端没有收到ACK
时,重新发送一次FIN
报文。
可以通过tcp_tw_reuse
来重用time_wait
状态的端口号。
shell
查询time_wait
连接
查看连接的状态,主要有两个命令netstat
和ss
。netstat
有的ss
都有,而且运行非常快。
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) {print a, S[a]} }'
匹配tcp
连接,声明了数组S
,$NF
用于获取最后一列的数据,也就是tcp status
,最后通过for
语句输出。
ss -o state time-wait '( sport = :http )' #timewait是中划线
通过ss
还可以方便的过滤出源端口是80的,状态是time_wait
的连接
总结
在开发中,可以适当考虑使用长连接。而且,现在基本所有的库都自带连接池功能。