咱们只知道在四次挥手的过程当中,先发起关闭的一方会进入TIME_WAIT状态,为何会出现TIME_WAIT状态以及TIME_WAIT状态过多,是什么缘由?shell
1 出现的场景
客户端在TCP创建链接对外提供服务的过程当中,每一个连接会占用一个本地端口,如在高并发的状况下,TIME_WAIT状态过多,势必会占用大量的端口,端口又有限,以至于耗尽端口,因此会出现偶尔连接的上,偶尔断开的状况编程
这么多的TIME_WAIT哪里来的呢?先复习下四次挥手网络
四次挥手并发
[FIN_WAIT1] :FIN_WAIT1和FIN_WAIT2均为等待对方的FIN报文。二者区别为,当SOCKET在ESTABLISHED状态时,想主动关闭链接从而想对方发送FIN报文,此时进入FIN_WAIT1状态。当收到ACK报文进入FIN_WAIT2状态。socket
[FIN_WAIT_2]:此状态下的socket实际上表示半链接的状态。什么是半链接,是一方想要关闭链接,另外一方说稍等下,我还有点数据给你tcp
[FIN_WAIT] :表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后便可回到CLOSED可用状态了ide
[CLOSE_WAIT] : 反过来读比较好,WAIT_CLOSE即「等待关闭」。在被动关闭链接状况下,在已经接收到FIN,可是尚未发送本身的FIN的时刻,链接处于CLOSE_WAIT状态。高并发
[LAST_ACK] :被动关闭乙方发送FIN后,等待对方的ACK,收到ACK即进入CLOSED状态优化
在TCP/IP协议栈中,假设主机A想要进行连接终止操做,因而发送FIN报文给主机B,主机B收到从而进入CLOSE_WAIT状态并发送ACK做为应答,同时主机B会告诉应用程序也要关闭操做,因而发送FIN报文。主机A收到FIN报文发送ACK表示收到并进入TIME_WAITui
在Linux系统中有一个字段,名称为TCP_TIME_WAIT_LEN,其数值为60s,也就是须要在TIME_WAIT阶段停留60s
2 TIME_WAIT什么做用
从上图咱们知道TIME_WAIT事后还有CLOSE状态,为何不直接进入CLOSED状态,而是要过一会呢?
第一点,在TIME_WAIT后,为了确保ACK能让被动方接收并辅助其关闭。假设这样的状况
若是主机A的ACK报文传输失败,那么在TCP/IP协议栈设计中,主机B会重传FIN报文,可是此时主机A没有维护好TIME_WAIT状态而是CLOSED状态,此时主机A只好发送RST,从而被动关闭失败。
第二点,为了让就链接的重复节点在网络中天然消失。怎么理解?
咱们知道,在网络传输的过程当中,总会由于各类故障致使报文不能准时到达目的地。如今咱们假设使用[源IP,源端口,目的IP,目的端口]表明链接A,在通讯的过程当中,连接A由于某种缘由中断,暂时迷路,从而建立了相似于A的链接B,但是迷路的链接A此时到达了,势必就会对TCP通讯产生影响。因此设置了2MSL,足够的时间让两个方向的分组都消失,使得下一个新的链接不会出现旧的链接请求报文
3 TIME_WAIT哪些危害
内存资源占用
端口占用。端口资源有限,通常可开启端口为32768~61000,能够经过修改net.ipv4.ip_local_port_range指定,若是TIME_WAIT太多将没法创建链接
你能够经过下面命令查看当前TIME_WAIT数量
这里为何是28233呢,取决于内核参数net.ipv4.ip_local_range
由于端口范围是一个闭区间,因此实际可用的端口数量是:
shell> echo $((61000-32768+1)) 28233
4 TIME_WAIT如何优化
暴力执法------net.ipv4.tcp_max_tw_buckets
一旦TIME_WAIT状态过多就重置,方法是使用sysctl将系统值减少,太粗鲁不推荐
调低 TCP_TIMEWAIT_LEN
了解内核编译便可操做
SO_LINGER设置,不推荐,由于它直接跳过TIME_WAIT
int setsockopt(int sockfd, int level, int optname, const void *optval,socklen_t optlen);
调整tcp_tw_recycle
咱们先看看RFC1323中怎么描述的
An additional mechanism could be added to the TCP, a per-hostcache of the last timestamp received from any connection.This value could then be used in the [PAWS] mechanism to rejectold duplicate segments from earlier incarnations of theconnection, if the timestamp clock can be guaranteed to haveticked at least once since the old connection was open. This would require that the TIME-WAIT delay plus the RTT togethermust be at least one tick of the sender’s timestamp clock.Such an extension is not part of the proposal of this RFC.
net.ipv4.tcp_tw_reuse 复用链接
使用这个选项有个前提,须要打开TCP时间戳的支持net.ipv4.tcp_time stamps=1,在RFC1323中,为了保证TCP的高可用,引入了两个4字节的时间戳选项,用于记录 TCP 发送方的当前时间戳和从对端接收到的最新时间戳。这就有意思了,以前说的2MSL就不存在了,由于若是重复的数据包会由于时间戳的过时而被丢弃
只适用于链接发起方(C/S 模型中的客户端),这里为何强调是客户端,咱们看看源码;
其调用路径仅仅出如今tcp_v4_connect->inet_hash_connect->__inet_check_established->twsk_unique->twsk_unique。 也就是说tcp_tw_reuse仅在TCP套接字做为客户端,调用connect时起做用。做为服务端不多主动发起连接,因此对于服务端而言不用打开此选项
对应的 TIME_WAIT 状态的链接建立时间超过 1 秒才能够被复用。
最后引用一下W. Richard Stevens在《UNIX网络编程》的一句话
The TIME_WAIT state is our friend and is there to help us (i.e., to let old duplicate segments expire in the network). Instead of trying to avoid the state, we should understand it.
译者:存在即合理,勇敢面对,而不是逃避。