优质博文:IT-BLOG-CN
灵感来源
Time_Wait 产生的时机
TCP
四次挥手的流程
如上所知:客户端在收到服务端**第三次
FIN
挥手**后,就会进入
TIME_WAIT
状态,开启时长为
2MSL
的定时器。
【1】
MSL
是
Maximum Segment Lifetime
报文最大生存时间,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为
TCP
报文是基于
IP
协议的,而
IP
头中有一个
TTL
字段,是
IP
数据报可以经过的最大路由数,每经过一个处理他的路由器值就会减
1
,当此值为
0
则数据报将会被丢弃,同时发送
ICMP
通知源主机;
**
MSL
与
TTL
的区别:**
MSL
单位是时间,
TTL
是经过路由跳数。所以
MSL
应该大于等于
TTL
消耗为
0
的时间,以确保报文已被自然消亡。
【2】
2MSL
的时间是从客户端接收到第三次握手的
FIN
后发送
ACK
开始计时的;
如果在
TIME-WAIT
时间内,因为客户端的
ACK
没有传输到服务端,客户端又收到了服务端重发的
FIN
报文,那么
2MSL
时间将重新计时。
【3】
Linux
系统停留在
TIME_WAIT
的时间为固定的
30
秒。这个数值是硬编码在内核中的,也就是说除非你重新编译内核,否则没法修改它;
#defineTCP_TIMEWAIT_LEN(60*HZ)
TTL
的值一般为
64
,
MSL
一般为
30s
,意味着
Linux
数据报文经过
64
个路由器时间不会超过
30s
,如果超过了则认为报文已经消息在网络中。
【4】客户端在收到服务端重传的
FIN
报文时,
TIME_WAIT
状态的等待时间会重置回
2MSL
;
2MSL
解释:网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又向对方发送响应,所以一来一回就是
2
个
MSL
时间。
如果被动关闭方
Server
没有收到断开连接的
ACK
报文,就会触发超时重发
FIN
报文,另一方
Client
接收到
FIN
后,会重发
ACK
给被动关闭方,一来一回正好
2
个
MSL
主动发起关闭连接的一方才会有
TIME-WAIT
状态。
为什么需要 TIME- WAIT状态
【1】确保被动关闭方已经关闭了连接: 当主动关闭方发出最后的
ACK
后,如果由于某种异常导致报文丢失,被动方没有收到最后的
ACK
报文会一直处于
LAST-ACK
状态,无法进入
CLOSED
状态。
假设主动关闭方跳过
TIME_WAIT
状态或者处于
TIME_WAIT
状态很短的时间后进入
CLOSED
状态,此时主动关闭方如果使用相同的源端口,发起
SYN
连接请求,被动关闭方由于还处于
LAST_ACK
状态,收到
SYN
包,此时就会回复
RST
包,导致新连接无法正常建立起来。
**【2】新的
TCP
连接被建立起来了,延迟包可能干扰新的连接:** 当使用原来的五元组来建立新的
TCP
连接,如果上一次连接还有数据报文,由于网络拥塞等原因,在新连接建立后才到达(且序列号一致),此时就会干扰到新的连接了,当然出现这种问题的概率比较低。
TIME_WAIT 资源使用情况
【1】查询方式: 通常在业务中可以使用
netstat
命令来查看系统的网络连接状态:
// 查看当前所有连接的状态,包括 TIME_WAIT 状态
netstat -an
// 查看指定 IP 地址和端口的连接状态
netstat -an | grep [IP]:[port]// 查看所有状态为 TIME_WAIT 的连接
netstat -an | grep TIME_WAIT// 查看所有 TIME_WAIT 状态的连接并统计数量
netstat -an | grep TIME_WAIT| wc -l
在
TCP
协议中,客户端通常会使用一个随机的端口号来与服务器建立连接。每一个
TIME_WAIT
状态,都会占用一个「本地端口」,上限为
65535
。本地端会等待两倍的
MSL
(
Maximum Segment Lifetime
,最大报文生存时间)的时间,这个时间通常为几分钟,之后才会释放该端口。如果这个时候新连接使用了这个端口,就可能出现数据混乱或者安全问题。
**【2】
TIME_WAIT
占用系统资源:** 整个系统建立连接时占用的资源:
☑️ **建立
TCP
连接**时,客户端需要指定目标服务器的
IP
地址和端口号,这个过程可能需要进行
DNS
查询和端口扫描等操作,这些操作可能会消耗一些资源
☑️ **短时间内频繁建立和关闭
TCP
连接** ,
TIME_WAIT
状态连接会占用系统的端口号和内存等资源,从而影响系统的性能
☑️ 随机端口号范围小了,引发端口号竞争, 临时端口号的竞争可能会导致
TCP
连接建立失败或者连接超时
**【3】
TIME_WAIT
与连接池的关系:** 使用连接池可以有效地减少连接的创建和关闭次数,从而减少
TIME_WAIT
状态下的连接数量。同时,连接池还可以通过控制连接数量、超时时间等参数,进一步优化连接的使用效率。
但是,如果连接池中存在大量的
TIME_WAIT
状态下的连接,那么连接池的效率可能会受到影响,从而导致系统性能下降。因此,需要通过调整连接池的参数,如最大连接数量、连接超时时间等,来避免
TIME_WAIT
问题的影响。
**【4】
TIME_WAIT
与
TCP_SYNC
**
**
TCP_SYNC
:** 攻击者利用伪造的
SYN
报文不断向受害者的服务器发送连接请求,但是连接并不能完成三次握手,最终服务器会不断创建半连接,引发系统崩溃。
攻击中,攻击者会大量发送伪造的
SYN
报文,但不回应服务器的
SYN+ACK
报文,从而使服务器不断等待客户端的
ACK
报文,最终导致服务器的连接队列被占满,无法响应正常连接请求。
TIME_WAIT
和
TCP_SYNC
本身没有联系,只是半连接在一定时间后会变成
TIME_WAIT
状态,就可以观测到
TIME_WAIT
数量增多。
**
TIME-WAIT
状态的危害:**
【1】占用系统资源: 如果服务端主动发起关闭连接方的
TIME-WAIT
状态过多。比如文件描述符、内存资源、
CPU
资源、线程资源等;
【2】端口资源: 如果客户端主动发起关闭连接方的
TIME-WAIT
状态过多。端口资源有限,一般可以开启的端口为
32768~61000
,也可以通过
net.ipv4.ip.local_port_range
参数指定范围。只要连接的是不同的服务器,端口还是可以重复使用的;
TIME-WAIT 优化
【1】
net.ipv4.tcp_tw_reuse
和
tcp_timestamps
:
net.ipv4.tcp_tw_reuse = 1
表示开启重用,允许将
TIME-WAIT socket
重新用于新的
TCP
连接。默认为
0
,表示关闭。
net.ipv4.tcp_tw_reuse =1
Linux
内核参数开启后,则可以复用处于
TIME_WAIT
的
socket
为新的连接所用。
.tcp_tw_reuse
功能只能为客户端为发起方,因为开启该功能,在调用
connect()
函数时,内核会随机找一个
time_wait
状态超过
1s
的连接给新的连接复用。
使用该选项的前提需要打开对
TCP
时间戳的支持,即:默认为
1
net.ipv4.tcp.timestamps=1
这个时间戳的字段是在
TCP
头部的选项里,它由一共
8
个字节表示时间戳,其中第一个
4
字节字段用来保存发送该数据包的时间,第二个
4
字节字段用来保存最近一次接收对方发送到达数据的时间。
由于引入了时间戳,前面提到的
2MSL
问题就不存在了,因为重复的数据包会因为时间戳过期被自然丢弃。
【2】
net.ipv4.tcp_max_tw_buckets
设置上限值,默认值为
18000
,当系统中处于
TIME_WAIT
的连接一旦超过这个值时,系统就会将后端的
TIME_WAIT
连接状态重置,比较暴力。
【3】
TCP
协议栈有个
keepalive
的属性,可以主动探测
socket
是否可用,不过这个属性的默认值很大。
全局设置可更改
/etc/sysctl.conf
,加上:
net.ipv4.tcp_keepalive_intvl =20 net.ipv4.tcp_keepalive_probes =3 net.ipv4.tcp_keepalive_time =60
在程序中设置如下:
int keepAlive =1;// 开启keepalive属性 int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测 int keepInterval =5;// 探测时发包的时间间隔为5 秒int keepCount =3;// 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.
版权归原作者 程序猿进阶 所有, 如有侵权,请联系我们删除。