HTTP和TCP的区别
HTTP和TCP是互联网技术的基础协议,分别位于应用层和传输层,承担不同的功能。HTTP主要负责网页内容的传输,而TCP负责在客户端和服务器之间建立可靠的数据连接。具体区别如下:
-
协议层级不同:HTTP是应用层协议,专注于数据内容的传输,如HTML文件、图像文件等;TCP(传输控制协议)是传输层协议,主要负责在客户端和服务器之间建立可靠的连接,确保数据传输的完整性和顺序性。
-
功能不同:HTTP采用请求-响应模型,主要用于传输网页内容和其他网络资源;TCP则提供可靠的传输服务,通过连接管理、错误校验和重传机制,确保数据包能够按顺序、无误地到达目的地。
-
连接方式不同:HTTP是一种无状态协议,每个请求和响应都是独立的,服务器不会保留前后请求的状态;而TCP是面向连接的协议,在数据传输前需要通过三次握手建立连接,并在传输完成后通过四次挥手释放连接。
-
数据传输方式不同:HTTP传输数据通常以文本或二进制形式进行,适用于高层应用的数据交换;TCP则提供基于字节流的传输服务,确保数据流能够稳定、连续地传输,即使在复杂的网络环境中也能保证数据的完整性。
-
应用场景不同:HTTP主要用于网页浏览、API调用等网络应用场景;而TCP则广泛应用于需要可靠数据传输的场景,如文件传输、电子邮件、远程登录等。
总结来说,HTTP依赖于TCP来建立数据传输的通道,而TCP为HTTP提供了可靠的传输服务。HTTP关注数据内容和格式,而TCP关注数据传输的可靠性和顺序性。
TCP三次握手的流程
-
第一次握手:SYN 报文
- 客户端随机生成一个初始序列号
client_isn
,并将其放入 TCP 首部的序列号字段,然后将 SYN 标志位设为 1,表示请求建立连接。 - 客户端将这个 SYN 报文发送给服务器,并进入 SYN-SENT 状态,等待服务器的响应。
- 客户端随机生成一个初始序列号
-
第二次握手:SYN+ACK 报文
- 服务器接收到客户端的 SYN 报文后,会生成自己的初始序列号
server_isn
,并将其放入 TCP 首部的序列号字段。 - 服务器将「确认应答号」字段填入
client_isn + 1
,同时将 SYN 和 ACK 标志位都设为 1,表示确认客户端的请求并且也希望建立连接。 - 服务器将 SYN+ACK 报文发送给客户端,然后进入 SYN-RECV 状态,等待客户端的确认。
- 服务器接收到客户端的 SYN 报文后,会生成自己的初始序列号
-
第三次握手:ACK 报文
- 客户端接收到服务器的 SYN+ACK 报文后,确认服务器的序列号
server_isn
,并将「确认应答号」字段填入server_isn + 1
。 - 客户端将 ACK 标志位设为 1,并将这个 ACK 报文发送给服务器,这次报文可以携带数据(但不强制必须携带)。
- 发送完 ACK 报文后,客户端进入 ESTABLISHED 状态,表示连接已建立并准备好进行数据传输。
- 服务器接收到客户端的 ACK 报文后,也进入 ESTABLISHED 状态,此时 TCP 连接已经建立,双方可以开始数据传输。
- 客户端接收到服务器的 SYN+ACK 报文后,确认服务器的序列号
通过这三次握手,TCP 协议确保了客户端和服务器双方都准备好建立连接并同步了初始序列号,从而保证了后续数据传输的可靠性。
以下是整理、修改错误并补充优化后的内容:
为什么需要三次握手?
TCP 三次握手的设计旨在确保通信双方都具有接收和发送数据的能力,并且能够同步初始序列号,以防止资源浪费和重复连接的初始化。
总结:
- 防止重复历史连接的初始化(主要原因)
- 同步双方的初始序列号
- 避免资源浪费
1. 防止重复历史连接的初始化(主要原因)
- 场景描述:假设因为网络延迟,客户端向服务器发送了两个 SYN 报文。由于某些原因,旧的 SYN 报文先到达了服务器。
- 处理过程:
- 服务器接收到旧的 SYN 报文后,发送 SYN+ACK 报文并进入半连接状态(SYN-RECV)。
- 客户端接收到这个 SYN+ACK 报文后,可以通过检查上下文(例如序列号过期或超时)判断这是一个历史连接,然后发送 RST 报文给服务器,终止这个连接。
- 服务器收到 RST 报文后,会释放这个连接资源。
- 当新的 SYN 报文到达时,客户端和服务器将进行正常的三次握手,建立新的连接。
- 两次握手的不足:如果采用两次握手,服务器在收到旧的 SYN 报文后就直接进入 ESTABLISHED 状态,不知道这是一个历史连接,可能会浪费资源去建立不必要的连接,直到客户端发送 RST 报文来断开连接。
因此,三次握手可以确保在服务器发送数据前,防止历史连接的建立。
2. 同步双方的初始序列号
TCP 协议中的序列号是实现可靠数据传输的关键因素,双方必须同步初始序列号,以确保数据的完整和顺序。
-
序列号的作用:
- 去除重复数据。
- 按序接收数据包。
- 标识哪些数据包已经被成功接收。
-
三次握手的过程:
- 客户端发送第一个 SYN 报文,携带客户端的初始序列号
client_isn
。 - 服务器接收到 SYN 报文后,返回 SYN+ACK 报文,携带服务器的初始序列号
server_isn
,并确认接收到客户端的序列号。 - 客户端收到服务器的 SYN+ACK 报文后,发送 ACK 报文,确认接收到服务器的序列号。
- 客户端发送第一个 SYN 报文,携带客户端的初始序列号
通过这三个步骤,确保了双方的初始序列号能够可靠地同步。
两次握手的问题:只进行两次握手时,仅能保证一方的序列号被另一方成功接收,无法确保双方的序列号都能被确认和同步。
四次握手的冗余:虽然四次握手也可以同步双方的序列号,但三次握手已经足以保证连接的可靠建立,增加一次握手并无必要。
3. 避免资源浪费
- 两次握手的弊端:
- 如果采用两次握手,客户端的 SYN 报文可能因为网络阻塞而需要重发,服务器每次接收到 SYN 报文都会创建一个新的连接。
- 由于没有第三次握手,服务器无法确认客户端是否接收到自己的 SYN+ACK 报文,因此可能会建立多个冗余的无效连接,造成资源浪费。
通过三次握手,服务器只有在确认客户端已接收到 SYN+ACK 报文后,才进入 ESTABLISHED 状态,从而避免资源浪费。
总结:
- 两次握手的缺陷:无法防止历史连接的建立,容易造成资源浪费,也无法可靠同步双方的序列号。
- 三次握手的必要性:三次握手能够防止历史连接的建立、减少资源浪费、并且同步初始化序列号,是建立可靠 TCP 连接的最少必要步骤。
以下是整理和补充后的内容:
什么是半连接队列?
半连接队列(SYN 队列)是用于存放已经发送了 SYN(同步)包但还未完成三次握手的连接。它在 TCP 协议中的作用是确保服务器能够正确处理和管理正在建立的连接。
工作过程:
- 当服务器第一次收到客户端发送的 SYN 报文时,服务器会进入 SYN-RECV 状态。
- 在这个状态下,服务器尚未与客户端完全建立连接,仅完成了三次握手中的第一步。
- 服务器会将这个处于未完全建立的连接放入 半连接队列 中,等待客户端发送确认报文(第三次握手)。
全连接队列(Accept 队列)则是用于存放已经完成三次握手,并处于完全建立连接状态的连接。完成三次握手后,连接会从半连接队列移入全连接队列,等待应用程序处理。
区别:
- 半连接队列:存放未完成三次握手的连接,连接尚未完全建立。
- 全连接队列:存放已完成三次握手、完全建立的连接,准备交给应用层处理。
这些队列的管理对于高并发服务器的性能和稳定性至关重要,尤其是在应对大量并发连接请求时。
什么是SYN攻击
SYN 攻击是一种常见的拒绝服务(Denial of Service, DoS)攻击方式,旨在通过耗尽服务器资源来使其无法正常处理合法请求。
- 攻击过程:
- 攻击者发送大量伪造的 SYN 请求到目标服务器。这些请求的源地址通常是伪造的,因此服务器无法与真实客户端建立连接。
- 服务器收到这些 SYN 请求后,会为每个请求分配资源并将其放入半连接队列,同时进入 SYN-RECV 状态,等待客户端的确认报文(ACK)。
- 由于这些 SYN 请求是伪造的,攻击者并不会发送后续的 ACK 报文,导致服务器一直在等待确认,连接无法完成。
- 影响:
- 服务器的半连接队列会被大量伪造的请求填满,从而无法再接受新的连接请求。
- 系统资源(如内存和 CPU)会被耗尽,导致服务器响应变慢甚至崩溃。
- 合法用户的连接请求可能会被拒绝或丢弃,导致无法正常访问服务器。
- 防御措施:
- SYN Cookies:服务器在收到 SYN 请求后不立即分配资源,而是通过计算哈希值的方式生成一个特殊的序列号(SYN Cookie),在客户端返回 ACK 时才进行资源分配。这种方式可以有效防止半连接队列被填满。
- 调整半连接队列大小:通过增大半连接队列的容量,可以提高服务器在短时间内应对大量 SYN 请求的能力。
- 减少 SYN-ACK 重传次数:通过减少服务器对未确认连接的重传次数,可以更快地释放被占用的资源。
SYN 攻击的本质是利用了 TCP 三次握手中的资源分配机制,因此对服务器资源的管理和防护非常重要。
除了SYN攻击,常见的网络攻击类型还有以下几种:
1. DDoS(分布式拒绝服务)攻击
- 概述:DDoS攻击通过分布在不同地理位置的大量设备(通常是僵尸网络)向目标服务器发送大量请求,导致服务器过载、无法处理正常流量,最终使得合法用户无法访问服务。
- 影响:服务器响应变慢或无法访问,甚至会导致服务器崩溃。
- 防御措施:
- 部署DDoS防护系统或服务
- 利用负载均衡和CDN(内容分发网络)分散流量
- 限制每个IP的请求频率
2. DNS放大攻击
- 概述:攻击者利用公开的DNS服务器发送大量请求,并伪造源IP地址为受害者的IP地址。DNS服务器响应的流量远大于请求的流量,从而放大攻击效果,使得受害者服务器承受巨大的网络流量压力。
- 影响:目标服务器或网络带宽被大量流量压垮,造成服务中断。
- 防御措施:
- 配置DNS服务器仅响应受信任的请求
- 使用DNS速率限制技术
- 部署DDoS防护措施
3. TCP连接耗尽攻击
- 概述:攻击者通过向目标服务器发送大量合法但持续占用资源的TCP连接,保持这些连接的活动状态,导致服务器资源被耗尽,无法再处理新的连接请求。
- 影响:服务器资源(如文件描述符、内存)耗尽,无法处理新连接请求,影响正常服务。
- 防御措施:
- 设置合理的连接超时时间
- 使用防火墙或网络设备限制单个IP的连接数量
- 实施TCP连接复用和限制
4. UDP洪泛攻击
- 概述:攻击者发送大量的UDP包到目标服务器,其中的目标端口通常是关闭的,导致服务器频繁回复ICMP不可达消息,从而消耗带宽和计算资源。
- 影响:服务器网络带宽被占用,导致正常流量无法到达,服务中断。
- 防御措施:
- 配置防火墙丢弃不必要的UDP流量
- 启用网络速率限制
- 使用DDoS防护工具或服务
5. ICMP洪泛攻击(Ping of Death)
- 概述:攻击者发送大量的ICMP Echo请求(Ping)数据包给目标服务器,消耗服务器的网络带宽和处理能力,使得服务器无法响应正常请求。
- 影响:服务器网络资源被耗尽,影响服务的正常运行。
- 防御措施:
- 配置防火墙过滤大量的ICMP流量
- 限制ICMP请求的频率
- 使用DDoS防护服务
6. HTTP洪泛攻击
- 概述:攻击者发送大量的HTTP请求到目标Web服务器,尤其是通过GET或POST请求,造成Web服务器资源耗尽或崩溃。
- 影响:Web服务器无法处理正常用户请求,导致网站服务中断。
- 防御措施:
- 使用Web应用防火墙(WAF)
- 启用请求速率限制
- 部署负载均衡和CDN来分散流量
这些攻击类型的核心目的是通过各种方式耗尽目标服务器的资源或网络带宽,造成服务中断或性能下降。通过合理的配置和防护措施,可以有效抵御这些攻击,保障网络和服务的稳定运行。
序列号
- 序列号:序列号是TCP协议中的一个重要头部字段,用于标识从TCP发送端到TCP接收端的数据流中的每个字节。由于TCP是面向字节流的可靠传输协议,为确保消息的顺序性和可靠性,TCP为传输的每个字节分配一个唯一的序列号。这些序列号的作用是便于数据在传输成功后进行确认、在丢失后进行重传,以及确保接收端的数据不会乱序。序列号是一个32位的无符号数,因此当序列号到达4G时,它将回绕至0继续计数。
- 初始序列号:在TCP建立连接的过程中,客户端和服务端都会各自生成一个初始序列号(Initial Sequence Number, ISN)。这个初始序列号是一个基于时钟生成的随机数,其目的在于确保每个TCP连接都拥有独立且不同的初始序列号,从而避免连接之间的冲突。初始序列号可以看作是一个32位的计数器,这个计数器的数值大约每4微秒加1,循环一次需要大约4.55小时。
- 序列号回绕:由于序列号是一个32位无符号数,它会在到达最大值4,294,967,295之后回绕至0。**序列号回绕意味着序列号并不是无限递增的,这也意味着在某些情况下,无法仅仅根据序列号来判断数据的先后顺序或新老状态。**这种情况要求TCP协议必须依赖其他机制(例如时间戳)来正确处理数据的顺序和可靠性,特别是在长时间运行的连接中。
TCP四次挥手
四次挥手的过程
在四次挥手开始之前,客户端和服务器都处于 ESTABLISHED 状态,表示连接已建立并且可以进行数据传输。
- 第一次挥手:
客户端决定关闭连接,向服务器发送一个带有TCP首部中FIN标志置 1 的FIN报文,并进入 FIN_WAIT_1 状态。这表示客户端已经不再发送数据,但仍然可以接收数据。 - 第二次挥手:
服务器收到客户端的FIN报文后,向客户端发送一个ACK应答报文,确认接收到FIN请求。此时,服务器将客户端的序列号+1作为ACK报文的确认序列号。服务器此时进入 CLOSE_WAIT 状态,表示它已收到关闭请求,但可能还有数据要发送给客户端。客户端收到ACK后进入 FIN_WAIT_2 状态等待服务端的 FIN。 - 第三次挥手:
服务器在处理完所有待处理的数据后,向客户端发送自己的FIN报文,表示它也打算关闭连接。服务器此时进入 LAST_ACK 状态,表示等待最后的ACK确认。 - 第四次挥手:
客户端收到服务器的FIN报文后,发送一个ACK应答报文,确认收到服务器的关闭请求。发送ACK后,客户端进入 TIME_WAIT 状态。在这个状态下,客户端等待一段时间(通常是2倍的最大报文生存时间,2MSL),以确保服务器已收到ACK报文,避免“丢失ACK”导致的连接重启问题。 - 服务器关闭:
服务器收到客户端的ACK报文后,直接进入 CLOSE 状态,表示服务器完成连接的关闭。 - 客户端关闭:
客户端在 TIME_WAIT 状态等待2MSL时间后,自动进入 CLOSE 状态,完成连接的关闭。此时,整个TCP连接正式关闭。
为什么断开连接需要四次挥手
关闭连接时,客户端发送FIN报文,表示其不再发送数据,但还可以接收数据。
服务端收到FIN报文,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,服务端可能还有数据需要处理和发送,所以先回一个ACK应答报文,等到其不再发送数据时,才发送FIN报文给客户端表示同意关闭连接。
从上面过程可知: 服务端通常需要等待完成数据的发送和处理,所以服务端的ACK和FIN一般都会分开发送,从而比三次握手导致多了一次。
为什么需要 TIME WAIT 状态
主动发起关闭连接的一方,才会有TIME-WAIT 状态。需要 TIME-WAIT 状态,主要是两个原因:
- 防止历史连接中的数据,被后面相同四元组 (相同目的端口、源端口、目的IP、源IP) 的连接错误的接收
- 在网络中,数据包有可能因为拥塞或延迟而滞留一段时间,甚至超过原始连接关闭的时间。如果没有 TIME-WAIT 状态,客户端直接进入 CLOSE 状态,这些滞留的数据包可能会在之后被传递给使用相同四元组(源端口、目的端口、源IP、目的IP)的新连接,导致新连接的数据被旧连接的数据干扰。
- TIME-WAIT 状态的持续时间是 2 倍的 MSL(Maximum Segment Lifetime,最大报文段生存时间),这个时间足够让网络中的旧数据包被丢弃,确保当新的连接建立时,不会受到旧连接数据的干扰。
- 保证「被动关闭连接」的一方能被正确的关闭,即保证最后的 ACK 能让被动关闭方接收,从而帮助其正常关闭。
- 在四次挥手的最后一步中,客户端会发送一个 ACK 报文来确认收到服务端的 FIN 报文。如果这个 ACK 报文丢失,而客户端已经直接进入 CLOSE 状态,那么服务端会一直等待这个 ACK,最终会重发 FIN 报文。
- 如果客户端处于 TIME-WAIT 状态,它可以接收服务端重传的 FIN 报文,并再次发送 ACK 进行确认,从而保证服务端能够正确关闭连接。如果没有 TIME-WAIT 状态,服务端在重传 FIN 后收到 RST(Reset)报文,会将其解释为一个错误,这样就可能导致连接关闭的不完全或异常。
- TIME-WAIT 状态的存在确保了在这个过程中,服务端能够最终接收到 ACK,从而成功关闭连接。如果服务端没有收到 ACK,那么就会触发 TCP 重传机制,服务端会重新发送一个FIN,这样一去一来刚好两个 MSL 的时间。
总结:
- 数据安全性:TIME-WAIT 状态可以防止旧连接的数据包被错误地接收到新连接中,确保数据的正确传输和安全性。
- 连接的正确关闭:TIME-WAIT 状态保证了四次挥手中的 ACK 报文能被服务端正确接收,从而确保服务端能够正常关闭连接。
为什么 TIME WAIT 等待的时间是 2MSL
- MSL (Maximum Segment Lifetime): 报文的最大生存时间,即任何报文在网络上存在的最长时间,超过这个时间,报文将被丢弃。
- 等待 2MSL 的原因:
- 防止旧数据包干扰新连接: 网络中可能存在延迟的数据包,这些数据包在 1 个 MSL 内可能还在传输中。等待 2MSL 可以确保所有旧连接的数据包都被自然消失,从而不会影响新连接。
- 确保 ACK 报文的可靠传输: 在四次挥手中,主动关闭方发送的最后一个 ACK 报文有可能丢失。如果在 1 个 MSL 时间内服务端没有收到这个 ACK 报文,就会重传 FIN 报文。此时,主动关闭方仍在 TIME WAIT 状态,可以继续接收这个重传的 FIN 报文并发送新的 ACK 报文。2MSL 时间可以确保 ACK 报文和重传的 FIN 报文都能正确传输,防止连接错误关闭。(1 个 MSL 确保四次挥手中主动关闭方最后的 ACK 报文最终能达到对端; 1 个 MSL 确保对端没有收到 ACK 重传的 FIN 报文可以到达。)
- 2MSL 的时间从主动关闭方接收到 FIN 后并发送 ACK 报文时开始计时。如果在 TIME WAIT 状态下,再次收到服务端重发的 FIN 报文,2MSL 时间将重新开始计时,以确保双方的连接完全关闭。
TIME WAIT 过多有什么危害?
- 占用系统资源: 每一个处于 TIME WAIT 状态的连接都会占用系统的资源,包括内存、文件描述符等。当服务器处理大量短连接时,若连接关闭后都进入 TIME WAIT 状态,会迅速占满系统资源,导致新的连接请求无法处理,可能引发系统性能下降或崩溃。
- 降低服务器并发能力: 处于 TIME WAIT 状态的连接无法立即释放,减少了系统可用的端口范围,特别是当同一对源地址和目的地址频繁建立和关闭连接时,可能会导致端口耗尽,进而影响服务器的并发处理能力。
- 增加系统负载: 当有大量的连接处于 TIME WAIT 状态时,系统需要维护这些连接的状态,增加了系统的管理负担,特别是在高并发环境下,可能导致 CPU 和内存的额外消耗,影响系统的整体性能。
- 导致网络端口耗尽: 在高流量应用中,短时间内可能会生成大量的 TIME WAIT 状态的连接,如果系统端口数被大量 TIME WAIT 连接占用,新的连接将无法建立,导致服务中断。
应对措施:
- 缩短 TIME WAIT 持续时间: 通过调整操作系统参数(如 tcp_tw_reuse 和 tcp_tw_recycle),可以适当缩短 TIME WAIT 状态的持续时间,缓解资源占用问题。
- 长连接代替短连接: 采用长连接来减少频繁的连接建立和关闭,从而降低 TIME WAIT 状态的数量。
- 负载均衡: 使用负载均衡将流量分发到多台服务器,减少单台服务器的 TIME WAIT 连接数。
TIME WAIT 的时间可以自己设置吗?过短或过长的影响
虽然 RFC 793 规定 MSL 为 2 分钟,但在实际的实现中,MSL 的时间会有所不同。例如,Linux 系统默认将 MSL 设置为 30 秒,这意味着 2MSL 的时间为 60 秒。
MSL 与 TTL 的区别:
- MSL(Maximum Segment Lifetime): 是指报文在网络中生存的最大时间,用时间表示。
- TTL(Time To Live): 是 IP 头部的一个字段,用于限制数据包经过的路由器数量。每经过一个路由器,TTL 就会减 1,当 TTL 减至 0 时,数据包将被丢弃。
关系与区别:
- MSL 是一个基于时间的限制,而 TTL 是基于路由跳数的限制。通常,MSL 的设置需要足够长,以确保在 TTL 耗尽之前,数据包能自然消失在网络中。
- TTL 一般默认值为 64,Linux 将 MSL 设置为 30 秒,意味着系统认为数据包经过 64 个路由器的时间不会超过 30 秒。
TIME WAIT 的时间可以设置吗?
- 可以: 操作系统允许调整 TIME WAIT 的时间。例如,在 Linux 中,可以通过修改内核参数(如 tcp_fin_timeout)来设置 TIME WAIT 的持续时间。
过短的影响:
-
数据错乱: 如果 TIME WAIT 时间过短,可能导致历史连接中的延迟数据包被新连接错误接收。例如,假设服务端在关闭连接前发送了一个 SEQ = 301 的数据包,由于网络延迟,该数据包在新连接建立后才抵达客户端。如果客户端未处于 TIME WAIT 状态,可能会将该延迟数据包视为新连接的数据,导致数据错乱。
-
连接重置错误: 若最后一个 ACK 报文丢失,服务端会重传 FIN 报文,而客户端可能已经进入 CLOSED 状态,此时会发送 RST 报文来回应 FIN。服务端接收到 RST 报文后,会将其解释为连接被对方重置,这是一种不优雅的连接终止方式。
过长的影响:
-
资源浪费: 过长的 TIME WAIT
会占用大量系统资源,如文件描述符和内存,尤其在高并发环境下,可能导致系统资源耗尽,影响服务器的性能。 -
减少并发连接数: 过长的 TIME WAIT 也会减少系统可用的端口范围,影响服务器的并发处理能力,可能导致新连接无法建立。
总结:
TIME WAIT 时间的设置应平衡安全性和系统性能,通常建议遵循系统默认设置,除非有特殊需求。
过短的 TIME WAIT 时间可能导致数据包错乱和不优雅的连接终止,而过长的 TIME WAIT 时间则可能导致资源浪费和并发能力下降。
tcp_tw_reuse
是什么
在 Linux 操作系统下,当连接关闭时,TIME_WAIT 状态的默认持续时间为 60 秒。这意味着在这段时间内,客户端会占用该连接的端口。由于端口资源有限(一般端口范围为 32768~61000),如果 TIME_WAIT 状态过多,可能会占满所有可用端口,导致无法创建新连接。
为了快速回收处于 TIME_WAIT 状态的连接,Linux 操作系统提供了两个系统参数:tcp_tw_reuse
和 tcp_tw_recycle
。这两个参数默认都是关闭的。
-
tcp_tw_reuse
:- 作用:该参数允许客户端(连接发起方)复用 TIME_WAIT 状态超过 1 秒的连接。如果该选项开启,客户端在调用
connect()
函数时,内核会随机选择一个 TIME_WAIT 状态超过 1 秒的连接进行复用。 - 适用场景:仅适用于连接发起方(客户端),有助于缓解因 TIME_WAIT 状态过多而导致的端口资源耗尽问题。
- 作用:该参数允许客户端(连接发起方)复用 TIME_WAIT 状态超过 1 秒的连接。如果该选项开启,客户端在调用
-
tcp_tw_recycle
:- 作用:该参数允许处于 TIME_WAIT 状态的连接被快速回收,加快端口资源的释放。
- 安全性:
tcp_tw_recycle
在 NAT(网络地址转换)环境下是不安全的,因为它可能导致之前的 SYN 报文被错误丢弃,因此在实际生产环境中通常不建议开启该选项。
时间戳选项 (tcp_timestamps
) 的必要性:
- 为了使
tcp_tw_reuse
和tcp_tw_recycle
生效,必须开启 TCP 时间戳功能,即net.ipv4.tcp_timestamps=1
(默认即为开启状态)。 - TCP 时间戳的作用:
- 精确计算 RTT(往返时间):时间戳使得传输层可以更准确地测量 RTT,从而更好地控制传输速率。
- 防止序列号回绕:序列号是 32 位无符号整数,最大值为 4GB。当网络速度足够快时,传输大量数据会导致序列号在较短时间内回绕,时间戳选项可以帮助识别并丢弃延迟到达的旧报文,避免数据混乱。
序列号回绕问题及 PAWS 防护机制:
- 假设 TCP 连接在传输大数据流(如 6GB)时,32 位序列号在时间点 D 和 E 之间发生回绕。如果丢失的报文在时间点 F 重新出现,而该报文的序列号恰好在接收窗口内,那么可能会导致数据完整性问题。
- PAWS(Protect Against Wrapped Sequence numbers)防护机制: 通过时间戳选项,TCP 可以有效防止序列号回绕带来的问题。PAWS 要求连接双方维护最近一次收到的数据包的时间戳值(Recent TSval),并在每次收到新数据包时进行比较。如果新数据包的时间戳值小于最近的有效时间戳值,PAWS 会将其视为过期报文并丢弃,确保数据完整性。
为什么 tcp_tw_reuse 默认是关闭的
tcp_tw_reuse 参数在 Linux 系统中默认是关闭的,主要原因在于安全性和协议的严格性考虑。以下是具体原因:
- 数据包混乱风险:
尽管 tcp_tw_reuse 可以加速 TIME_WAIT 状态的端口复用,但它也可能导致历史连接中的数据包被错误地关联到新的连接上。尤其是在网络出现延迟或拥塞的情况下,旧连接的数据包可能滞留在网络中,复用端口后,这些数据包可能被错误地认为是新连接的一部分,导致数据错乱。 - 潜在的安全隐患:
tcp_tw_reuse 的启用可能会让攻击者利用 TIME_WAIT 状态的连接发起重放攻击(Replay Attack)。攻击者可能通过复用旧连接的数据包来干扰新的连接,从而导致不安全的通信环境。 - 不符合 TCP 协议规范:
TCP 协议的设计初衷就是为了确保连接的可靠性和数据传输的有序性。TIME_WAIT 状态的存在是为了确保连接的完全关闭并避免旧数据包对新连接的干扰。启用 tcp_tw_reuse 会打破这种设计,违背了 TCP 协议的初衷。 - 实际使用场景的局限性:
tcp_tw_reuse 主要适用于一些客户端连接频繁的场景,但在大多数情况下,特别是涉及到服务器端的应用,直接开启该选项并不合适。因此,系统默认选择关闭这个参数,以避免可能的副作用。 - TCP 时间戳依赖:
tcp_tw_reuse 功能依赖于 TCP 时间戳 (tcp_timestamps) 选项。如果系统环境中没有开启时间戳或者时间戳机制不健全,开启 tcp_tw_reuse 可能会导致序列号回绕问题难以解决,从而增加网络不稳定性的风险。
总的来说,默认关闭 tcp_tw_reuse 是为了保证系统的安全性、数据传输的可靠性,以及符合 TCP 协议规范的要求。在实际应用中,是否启用 tcp_tw_reuse 需要根据具体的网络环境和应用需求谨慎决定。
小结
tcp_tw_reuse 的作用是让客户端快速复用处于 TIME_WAIT 状态的端口,相当于跳过了 TIME_WAIT 状态,这可能会出现这样的两个问题:
- 历史 RST 报文可能会终止后面相同四元组的连接,因为 PAWS 检查到即使 RST 是过期的,也不会丢弃。
- 如果第四次挥手的 ACK 报文丢失了,有可能被动关闭连接的一方不能被正常的关闭。
虽然 TIME_WAIT 状态持续的时间是有一点长,显得很不友好,但是它被设计来就是用来避免发生乱七八糟的事情。
《UNIX网络编程》一书中却说道:TIME_WAIT 是我们的朋友,它是有助于我们的,不要试图避免这个状态,而是应该弄清楚它。
TCP 同时关闭会发生什么
TCP 同时关闭(Simultaneous Close)指的是通信双方几乎在同一时间发起连接关闭操作的情况。这种情况虽然较为少见,但在某些场景中可能会发生,例如双方的应用程序都决定同时关闭连接。
在 TCP 同时关闭的情况下,通信双方都会发送一个 FIN
报文,过程如下:
-
双方都发送 FIN 报文:
假设客户端和服务器同时决定关闭连接,双方都会几乎在同一时间发送FIN
报文,并进入FIN_WAIT_1
状态。 -
双方都收到对方的 FIN 报文:
- 由于双方几乎同时发送
FIN
报文,这两个FIN
报文在网络上传递时,双方都会在接收到对方的FIN
报文后,回送一个ACK
报文,确认已接收到对方的关闭请求。 - 当客户端和服务器接收到
FIN
报文后,状态会从FIN_WAIT_1
变为CLOSING
。
- 由于双方几乎同时发送
-
双方都进入 TIME_WAIT 状态:
双方在发送ACK
报文并收到对方的ACK
报文确认后,都会进入TIME_WAIT
状态。此时,双方的连接进入关闭阶段,并保持TIME_WAIT
状态一段时间(通常为 2MSL)以确保最后的 ACK 报文能够可靠地传输到对方,避免因 ACK 丢失导致的连接未正常关闭。 -
最终关闭连接:
在TIME_WAIT
状态经过 2MSL 时间后,双方都会进入CLOSED
状态,彻底关闭连接。
特点与影响
-
双向确认:在同时关闭的情况下,双方都发送并接收了
FIN
和ACK
报文,保证了连接的双向确认和对等关闭。 -
增加的 TIME_WAIT 状态:由于双方都经历了
TIME_WAIT
状态,意味着双方的端口在 2MSL 时间内都会被占用,这在高并发的情况下可能增加系统的端口压力。 -
协议的可靠性:即使同时关闭,TCP 仍然能够通过四次挥手的机制确保连接的可靠性和数据传输的有序性。
总的来说,TCP 同时关闭并不会影响协议的正常运行,仍然能够通过标准的四次挥手过程完成连接的优雅关闭。