问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

TCP协议的"三次握手"过程分析及超时重传机制详解

创作时间:
作者:
@小白创作中心

TCP协议的"三次握手"过程分析及超时重传机制详解

引用
CSDN
1.
https://blog.csdn.net/dxyt2002/article/details/139722089

TCP协议是互联网通信的基础协议之一,其"三次握手"过程是建立可靠连接的关键步骤。本文将详细介绍TCP协议的"三次握手"过程及其重要性,帮助读者深入理解TCP协议的工作原理。

TCP的"三次握手"

TCP协议是有连接的传输层协议,即使用TCP协议通信,是需要建立连接的。TCP协议建立连接的过程,叫做"三次握手",这个过程具体是什么?为什么是三次?这两个问题可以分析一下。

TCP"三次握手"建立连接的过程,用图片展示是这样的:

注意,通信中发送的SYN、SYN+ACK、ACK,并不是发送报文中携带的数据,而是指发送的报文报头中设置的标记位。此图中,Client代表客户端,Server代表服务端,不同颜色的片段表示不同的状态。

那么,这个"三次握手"的过程就是:

  1. 客户端先发送连接请求,即 将TCP报文中SYN标记位设置为1,然后再将整个报文发送给服务端(一般情况下不会携带数据)。客户端发送了此报文之后,客户端进入SYN_SENT状态,表示已发送了建立连接的请求。
  2. 如果服务端收到了客户端发送的连接请求,那么服务端就会应答客户端的请求,即 将TCP报文中SYN和ACK标记位都设置为1,然后再将整个应答报文发送给客户端(同样一般不会携带数据)。服务端发送了此应答报文之后,服务端进入SYN_RCVD状态,表示已经应答了客户端的连接请求。
  3. 然后客户端就应该收到来自服务端的应答报文 之后,客户端就需要再向服务端发送一个应答,即 客户端将TCP报文中ACK标记位设置为1,然后将报文发送给服务端。客户端发送了此次应答报文之后,客户端就会进入ESTABLISHED状态,客户端认为连接建立成功。
  4. 最后,服务端应该收到来自客户端的应答报文,收到之后,服务端不会再发送应答报文,而是进入ESTABLISHED状态,服务端认为连接建立成功。

"三次握手"的实际就是 客户端和服务端在互相发送报文,用来确认连接的过程。

如何理解简单TCP的连接

连接,在网络中是一个比较抽象的概念。TCP协议是面向连接的,那么 如何理解TCP连接呢?

一个主机是可以同时建立大量的连接的,那么操作系统就需要同时维护、管理大量的连接。按照以往操作系统管理大量进程、文件等的经验,操作系统一定会针对每个连接 均维护 包含此连接所有属性的结构体。不过,由于TCP连接的管理较为复杂,所以对应需要维护的结构体不止一个。

那么,也就是说,当客户端或服务端为了维护TCP连接 创建了对应的结构体对象 并 已经完成了结构体内数据的填充,就表示 客户端或服务端认为此次TCP连接已完成且成功。

为什么是"三次握手"

上面介绍了"三次握手"的过程,但是为什么是三次?

一次不行吗?

我们已经了解到,当服务端针对此次TCP连接 创建并维护了对应的结构体对象 并 完成了结构体数据的填充时,服务端就认为连接建立完成。既然是操作系统创建维护一些结构体,那么就一定有时间和资源上的消耗。

如果是"一次握手",就表示 客户端发送SYN连接请求之后,就直接认为自己创建好了连接,服务端收到请求 不需要应答,服务端就同样直接认为连接已建立。

虽然,"一次握手"也同样可能成功的建立连接。但是,如果只是"一次握手" 就会出现一些问题:

  1. 客户端和服务端无法正确协定、同步 双方的初始序号。TCP报头存在序号,此字段的初始值是在建立连接时,客户端和服务端互相协定、同步的。如果只是"一次握手",那么只能同步客户端的初始序号,因为只有客户端发送了携带初始序号的报文。
  2. 由于网络延迟,客户端可能多次发送连接请求,服务端就有可能多次建立连接。服务端多次建立了连接,即 多次创建了 一些维护连接所需的结构体,但是只有一套是有效的。这样,会造成对服务端资源的无效占用。

两次不行吗?

如果是"两次握手",就表示 客户端先发送SYN连接请求,服务端收到请求 需要SYN+ACK应答,然后服务端认为连接建立完成,客户端收到服务端的应答之后,客户端认为连接建立完成。

我们知道,客户端和服务端认为连接建立完成的标志是 系统已经创建并填充完成了 一系列维护TCP连接所需的结构体。那么如果"两次握手",则是服务端系统先完成了 创建并填充 一系列维护连接所需的结构体。

这就可能出现一个问题:如果客户端不断地发送请求,但是不接收服务端的请求,然后导致 服务端不断地 维护TCP连接,而客户端并不维护连接。这就实现了对服务端主机的攻击:服务端会不断地消耗时间和空间资源,用于维护TCP连接,而客户端不会。

并且,由于服务端依旧是 仅接收一次客户端的报文 就确认连接已建立,所以还可能会出现 仅"一次握手"出现的问题:

  1. 由于网络延迟,客户端可能多次发送连接请求,服务端就有可能多次建立连接。服务端多次建立了连接,即 多次创建了 一些维护连接所需的结构体,但是只有一套是有效的。这样,会造成对服务端资源的无效占用。

“两次握手”,理论上来说 不会出现无法协定、同步通信双方初始序号的问题:

因为,客户端发送连接请求可以携带初始序号,服务端进行应答也可以携带初始序号。即使存在网络延迟,导致客户端发送了多个连接请求。服务端也会针对多个连接请求一一进行应答。所有应答报文都会填充对应的确认序号和初始序号,所以客户端只要收到了应答报文,就可以确认服务端应答的目标 以及 服务端的初始序号。然后,连接建立成功。

如果,客户端没有收到应答报文,那就意味着连接还没有建立成功,客户端可能会继续发送请求,直到成功接收应答报文。

如果是三次呢?

"三次握手"的过程已经简单的分析了一下。从图中可以看到,Client率先进入了ESTABLISHED状态,也就是说Client率先完成了维护TCP连接操作。然后,Server进入了ESTABLISHED状态,这样 让客户端先完成维护连接的操作,可以避免像"两次握手"那样 服务端被攻击,至少客户端也要付出相同的代价。

其次,因为在Client和Server进入ESTABLISHED状态之前,都经历了一收一发,所以不会出现 无法正确协定和同步双方初始序号的情况。

并且,"三次握手"通过三次报文传输,顺便完成了 客户端的发送(SYN请求)和接收(SYN+ACK应答)能力的检测 以及 服务端的发送(SYN+ACK应答)和接收(ACK应答)能力的检测。

"三次握手"是可以完成上面这些功能的最少的次数,如果"四次握手"或更多次数的握手,也只是徒增连接消耗罢了。

协定、同步双方初始序号

上面展示"三次握手"过程的图,没有展示出 通信双方同步初始序号的过程。"三次握手"过程可以这样展示:

  • SYN
  • ACK

大写的,表示设置的标记位

  • seq
  • ack

小写的,表示序号 和 确认序号

整个 协定、同步初始序号的过程是:

  1. 客户端发送连接请求,携带随机初始序号的seq = x
  2. 服务端收到请求,读取到客户端的初始序号,应答报文 携带随机初始序号的seq = y,且填充确认序号ack = x+1
  3. 客户端收到应答,读取确认序号 确认服务端已同步客户端初始序号,同时读取到服务端的初始序号,然后 应答报文 填充序号seq = x+1和确认序号ack = y+1。客户端确认连接建立
  4. 服务端收到应答,读取确认序号 确认客户端已同步服务端初始序号。服务端确认连接建立

整个过程中,客户端和服务端,都是经过一发一收 读取收到确认序号之后,才确认的初始序号已同步。"一次握手"和"两次握手"无法完善这个过程。

了解了"三次握手"的过程,回到上面提到的一个问题:发送方如何在第一次发送数据之前,就知晓接收方的窗口大小呢?这个答案就是:双方会在"三次握手"阶段对窗口大小进行交换、同步

RST标记位

"三次握手"的过程中,报文的发送是需要时间的。在客户端进行第三次握手之后,客户端实际就已经认为本次TCP连接已经建立完成了。客户端完成连接建立之后,会干什么?会向服务端发送数据。

但是,有一个问题是,如果服务端没有收到第三次握手的报文,但是客户端已经向服务端开始发送数据了,怎么办?在服务端还在等待第三次握手的报文时,服务端还没有进入ESTABLISHED状态,客户端已经发送通信数据到服务端了,此时服务端就会意识到TCP连接出了问题。

然后 服务端就会向客户端发送 设置了RST标记位的报文,让客户端重置TCP连接并重新进行"三次握手"。这就是RST标记位的作用,让客户端重新建立TCP连接,所以RST标记位 叫做复位标记位。

除了上面出现的场景,RST还可以用于由于长时间不进行通信,被服务器单方面断掉的TCP连接中。

TCP的超时重传机制

TCP的超时重传机制表示,在TCP通信中,如果一端长时间没有收到来自对端的应答,那么就会重新发送没有收到应答的报文。但是,长时间没有收到对端应答有两种情况:

  1. 报文根本就没有发送到对端,在传输过程中丢包了
  2. 对端接收到报文了,但是对端的应答却在传输的过程中丢包了

这两种情况的区别是:

  1. 对端没收到数据

  2. 对端收到了数据

  3. 对端没有收到数据

此时,只需要在超时之后 将报文重新发送给对端 就可以了

  1. 对端收到了数据

如果对端已经收到了数据,但是对端的应答报文丢了。那么,当报文重新发送给对端之后,对端会再次发送应答报文。但是,此时对端就会接收到重复的数据。但重复的报文、数据是没用的 需要丢弃,所以TCP协议需要有能力识别接收的报文是否重复。这就要用到TCP报文的序号字段。只要两个报文的序号字段相同,就说明收到了相同的报文。

TCP协议的超时重传机制,说明了TCP报文在发送出去 或 接收到之后,并不会立刻丢弃,而是会存储一段时间。这也是TCP超时重传机制的基础。

那么,TCP如何界定 是否超时?最理想的情况,就是可以找到一个最短的时间,保证此次发送之后"确认应答一定能在这个时间内返回"。但是,网络环境是会变化的,所以这个最短的时间也是不可能固定下来的。所以Linux中TCP协议就需要自行的界定、计算 超时边界。不过,重传不会一直进行,当重传累计到一定的重传次数,TCP认为网络或者对端主机出现异常,强制关闭连接。

关于超时的设定:

如果超时时间设的太长,会影响整体的重传效率。如果超时时间设的太短,有可能会频繁发送重复的包。

至此,本篇文章主要内容结束。感谢阅读~

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号