TCP 协议的 time_wait 超时时间

程序猿进阶 2024-08-16 15:07:04 阅读 68

优质博文:IT-BLOG-CN

灵感来源

在这里插入图片描述

Time_Wait 产生的时机

<code>TCP四次挥手的流程

在这里插入图片描述

如上所知:客户端在收到服务端第三次<code>FIN挥手后,就会进入TIME_WAIT状态,开启时长为2MSL的定时器。

【1】MSLMaximum Segment Lifetime报文最大生存时间,他是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为TCP报文是基于IP协议的,而IP头中有一个TTL字段,是IP数据报可以经过的最大路由数,每经过一个处理他的路由器值就会减1,当此值为0则数据报将会被丢弃,同时发送ICMP通知源主机;

MSLTTL的区别: MSL单位是时间,TTL是经过路由跳数。所以MSL应该大于等于TTL消耗为0的时间,以确保报文已被自然消亡。

【2】2MSL的时间是从客户端接收到第三次握手的FIN后发送ACK开始计时的;

如果在TIME-WAIT时间内,因为客户端的ACK没有传输到服务端,客户端又收到了服务端重发的FIN报文,那么2MSL时间将重新计时。

【3】Linux系统停留在TIME_WAIT的时间为固定的30秒。这个数值是硬编码在内核中的,也就是说除非你重新编译内核,否则没法修改它;

#define TCP_TIMEWAIT_LEN (60*HZ)

TTL的值一般为64MSL一般为30s,意味着Linux数据报文经过64个路由器时间不会超过30s,如果超过了则认为报文已经消息在网络中。

【4】客户端在收到服务端重传的FIN报文时,TIME_WAIT状态的等待时间会重置回2MSL

2MSL解释:网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又向对方发送响应,所以一来一回就是2MSL时间。

如果被动关闭方Server没有收到断开连接ACK报文,就会触发超时重发FIN报文,另一方Client接收到FIN后,会重发ACK给被动关闭方,一来一回正好2MSL

主动发起关闭连接的一方才会有TIME-WAIT状态。

为什么需要 TIME- WAIT状态

【1】确保被动关闭方已经关闭了连接: 当主动关闭方发出最后的ACK后,如果由于某种异常导致报文丢失,被动方没有收到最后的ACK报文会一直处于LAST-ACK状态,无法进入CLOSED状态。

假设主动关闭方跳过TIME_WAIT状态或者处于TIME_WAIT状态很短的时间后进入CLOSED状态,此时主动关闭方如果使用相同的源端口,发起SYN连接请求,被动关闭方由于还处于LAST_ACK状态,收到SYN包,此时就会回复RST包,导致新连接无法正常建立起来。

在这里插入图片描述

【2】新的<code>TCP连接被建立起来了,延迟包可能干扰新的连接: 当使用原来的五元组来建立新的TCP连接,如果上一次连接还有数据报文,由于网络拥塞等原因,在新连接建立后才到达(且序列号一致),此时就会干扰到新的连接了,当然出现这种问题的概率比较低。

在这里插入图片描述

TIME_WAIT 资源使用情况

【1】查询方式: 通常在业务中可以使用<code>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。本地端会等待两倍的MSLMaximum Segment Lifetime,最大报文生存时间)的时间,这个时间通常为几分钟,之后才会释放该端口。如果这个时候新连接使用了这个端口,就可能出现数据混乱或者安全问题。

【2】TIME_WAIT占用系统资源: 整个系统建立连接时占用的资源:

☑️ 建立TCP连接时,客户端需要指定目标服务器的IP地址和端口号,这个过程可能需要进行DNS查询和端口扫描等操作,这些操作可能会消耗一些资源

☑️ 短时间内频繁建立和关闭TCP连接TIME_WAIT状态连接会占用系统的端口号和内存等资源,从而影响系统的性能

☑️ 随机端口号范围小了,引发端口号竞争, 临时端口号的竞争可能会导致TCP连接建立失败或者连接超时

【3】TIME_WAIT与连接池的关系: 使用连接池可以有效地减少连接的创建和关闭次数,从而减少TIME_WAIT状态下的连接数量。同时,连接池还可以通过控制连接数量、超时时间等参数,进一步优化连接的使用效率。

但是,如果连接池中存在大量的TIME_WAIT状态下的连接,那么连接池的效率可能会受到影响,从而导致系统性能下降。因此,需要通过调整连接池的参数,如最大连接数量、连接超时时间等,来避免TIME_WAIT问题的影响。

【4】TIME_WAITTCP_SYNC

TCP_SYNC 攻击者利用伪造的SYN报文不断向受害者的服务器发送连接请求,但是连接并不能完成三次握手,最终服务器会不断创建半连接,引发系统崩溃。

攻击中,攻击者会大量发送伪造的SYN报文,但不回应服务器的SYN+ACK报文,从而使服务器不断等待客户端的ACK报文,最终导致服务器的连接队列被占满,无法响应正常连接请求。

TIME_WAITTCP_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_reusetcp_timestampsnet.ipv4.tcp_tw_reuse = 1表示开启重用,允许将TIME-WAIT socket重新用于新的TCP连接。默认为0,表示关闭。

net.ipv4.tcp_tw_reuse = 1

Linux内核参数开启后,则可以复用处于TIME_WAITsocket为新的连接所用。

.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次的不再发.



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。