10 TIME_WAIT(发起连接终止的一方才会进入)
发生场景:
TIME_WAIT状态的连接过多,多到把本机可用的端口耗尽,对外表现的症状就是不能正常工作了。过了一段时间后,处于TIME_WAIT的连接被系统回收并关闭,释放出本地端口,可以正常工作。这样周而复始,便会出现一会不可以,一会可以正常工作的现象。
四次挥手过程:
TCP 连接终止时,主机 1 先发送 FIN 报文,主机 2 进入 CLOSE_WAIT 状态,并发送一个 ACK 应答,同时,主机 2 通过 read 调用获得 EOF,并将此结果通知应用程序进行主动关闭操作,发送 FIN 报文。主机 1 在接收到 FIN 报文后发送 ACK 应答,然后进入 TIME_WAIT 状态。
?主机 1 在 TIME_WAIT 停留持续时间是固定的,是最长分节生命期 MSL(maximum segment lifetime)的两倍,一般为 2MSL。Linux 系统里有一个硬编码的字段,名称为TCP_TIMEWAIT_LEN,其值为 60 秒。也就是说,Linux 系统停留在 TIME_WAIT 的时间为固定的 60 秒。
为什么要四次不是三次
FIN请求仅代表发送方的数据传输已完毕,并不代表本次TCP连接断开。接收方在接收到对方的FIN并回复ACK之后,仍然能够传输数据,直到接收方自身数据传输完毕。接收方自身再发送FIN,对端回复ACK后,才代表本次回话结束
TIME_WAIT的作用:
1.确保最后的ACK能让被动关闭方接收,从而帮助其正常关闭(ACK报文没有传输成功时,主机2就会重新发送FIN报文,所以要多停留一会)
?2.防止报文迷走的危害,让旧连接的重复分节在网络中自然消失。
在原连接中断后,又重新创建了一个原连接的“化身”,说是化身其实是因为这个连接和原先的连接四元组完全相同(源和目标的ip+端口),如果迷失报文经过一段时间也到达,那么这个报文会被误认为是连接“化身”的一个 TCP 分节,这样就会对 TCP 通信产生影响。
所以,TCP 就设计出了这么一个机制,经过 2MSL 这个时间,足以让两个方向上的分组都被丢弃,使得原来连接的分组在网络中都自然消失,再出现的分组一定都是新化身所产生的。
TIME_WAIT的危害:
1.内存资源占用,这个目前看来不是太严重,基本可以忽略。
2.对端口资源的占用,一个 TCP 连接至少消耗一个本地端口。如果 TIME_WAIT 状态过多,会导致无法创建新连接。这个也是我们在一开始讲到的那个例子。
优化TIME_WAIT
1.暴力法:通过sysctl命令将系统默认值18000调小,TIME_WAIT连接数一旦超过这个值,系统就会为所有的TIME_WAIT连接状态重置,并且只打印出警告信息。治标不治本,带来的问题比解决的问题多,不推荐。
2.危险:设置so_linger,linger意思为停留,我们可以通过设置套接字选项来设置调用close或者shutdown关闭连接时的行为,具体见https://time.geekbang.org/column/article/125806
3.更安全:net.ipv4.tcp_tw_reuse选项,如果安全可控,可以复用处于TIME_WAIT的套接字为新的连接所用。