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

TCP协议的"三次握手"过程详解:为什么需要三次握手?

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

TCP协议的"三次握手"过程详解:为什么需要三次握手?

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

TCP协议的"三次握手"是建立可靠连接的关键过程。本文将详细解析三次握手的具体步骤、为什么需要三次握手,以及TCP的超时重传机制。

TCP的"三次握手"

TCP协议是有连接的传输层协议,使用TCP协议通信需要建立连接。TCP协议建立连接的过程叫做"三次握手"。

这个过程具体如下:

  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号