太阳不下山 发表于 2021-7-5 12:03:44

TCP协议中的三次握手和四次挥手,一个同同事互水的技术话题(经典面试题目)

  
  TCP协议中的三次握手和四次挥手

[*]

[*]1.前言
[*]2. TCP经典通信状态流转

[*]2.1 Client状态经历过程
[*]2.2 Server状态经历过程

[*]3.TCP通信过程

[*]3.1 TCP报文
[*]3.2 TCP通信三阶段

[*]3.2.1 建立连接阶段(三次握手Hello)

[*]3.2.1.1 第一次握手 ——你好,我是你的粉丝张三,很高兴认识你
[*]3.2.1.2 第二次握手 ——你好,我是单片机菜鸟哥,很高兴认识你+1
[*]3.2.1.3 第三次握手 ——很好,我们可以开始技术交流了
[*]问题1:两次握手可以吗?
[*]问题2:三次握手就可以了吗?是否考虑4次?

[*]3.2.2 断开释放连接阶段(四次挥手拜拜)


[*]4.总结



  
1.前言
  通常,建立TCP需要三次握手才能建立,而断开连接则需要四次握手。
  然而,昨晚同事就这个问题抛出了自己的疑问点:

[*]建立TCP,为什么不能两次握手呢?
[*]为什么三次握手就有保证呢?是不是可能需要四次握手呢?
  因此,记录一下笔记。我们的讨论内容涉及到:

[*]网络链路重传、网络链路延迟
[*]服务端资源消耗
[*]网络***、网络

2. TCP经典通信状态流转
  首先,来一张经典图片:


2.1 Client状态经历过程
  从client(客户端)来看,状态机包括6种状态,分别为:

[*]Closed
[*]SYN-SEND
[*]ESTABLISED
[*]FIN-WAIT-1
[*]FIN-WAIT-2
[*]TIME-WAIT
2.2 Server状态经历过程
  从Server(服务端)来看,状态机包括6种状态,分别为:

[*]Closed
[*]LISTEN
[*]SYN_RCVD
[*]ESTABLISED
[*]CLOSE_WAIT
[*]LAST_ACK

3.TCP通信过程
  在了解阶段过程之前,先看看TCP报文。
3.1 TCP报文
  
比较重要的字段有:
1.序号(sequence number):占4个字节,指本报文段所发送的数据的第一个字节的序号。
  2.确认号(acknowledgement number):同样占4个字节,是期望收到对方下一个报文段的第一个字节的序号。(即收到对方的报文段最后一个字节的序号加一)(序号和确认号是TCP可靠传输的关键部分)
  3.(部分)标志位(Flags)

[*]确认(ACK):只有标志位ACK=1时确认号字段(acknowledgement number)才有效;(注意区分 确认号ACK 和 标志位 ACK)
[*]同步(SYN):SYN=1表示这是一个“连接请求(SYN)”或“连接接受(SYN-ACK)”报文;
[*]终止(FIN):用于释放连接,FIN=1表明报文段发送完毕,要求释放连接。
  4.窗口:占2字节,窗口大小最大为65535,是用来让对方设置发送窗口的依据。滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。
3.2 TCP通信三阶段
  整个TCP通信可以分为三个阶段:

[*]建立连接阶段(三次握手Hello)
[*]数据传输阶段(多次传输数据,不是本次重点)
[*]断开释放连接阶段(四次挥手拜拜)
3.2.1 建立连接阶段(三次握手Hello)
  所谓的三次握手,其实就是TCP连接的建立过程。
  
这里可以简单概括为影响了三个状态(不管是客户端还是服务器):

[*]CLOSED(简称C)
[*]SYN(简称S)
[*]ESTABLISHED(简称E)
  这里以一个业务场景来讲述握手协议:

[*]单片机菜鸟哥现场解答众粉丝技术问题(鸟哥作为服务端,众粉丝作为众客户端)
3.2.1.1 第一次握手 ——你好,我是你的粉丝张三,很高兴认识你
  握手流向:客户端 ——>服务端
  场景说明:

[*]你好,我是你的粉丝张三,很高兴认识你
  协议说明:

[*]客户端主动往服务端发起SYN(Seq = X)的报文,表示 请求建立新连接,随后进入 SYN 状态(从 CLOSED状态切换到SYN状态)

3.2.1.2 第二次握手 ——你好,我是单片机菜鸟哥,很高兴认识你+1
  握手流向:客户端 <——服务端
  场景说明:

[*]你好,我是单片机菜鸟哥,很高兴认识你+1
  协议说明:

[*]服务端在 LISTEN 状态下收到客户端的SYN报文后,会给客户端返回响应应答 SYN +ACK(Seq = Y,Ack = x +1,表示收到客户端的Seq号),随后进入 SYN 状态(服务端从LISTEN状态下切换到SYN状态)

3.2.1.3 第三次握手 ——很好,我们可以开始技术交流了
  握手流向:客户端 ——>服务端
  场景说明:

[*]很好,我们可以开始技术交流了,这个时候鸟哥就可以开始进入粉丝答疑环节。
  协议说明:

[*]客户端收到 SYN+ACK 包之后,回复给服务端一个ACK(Seq = x+1,Ack = y + 1,Ack等于服务端Seq +1,表示收到服务端的Ack),然后进入到 ESTABLISHED 状态
[*]服务端收到 ACK 包之后,知道客户端收到了自己的应答,也进入到 ESTABLISHED 状态
[*]双方开始正常通信

整个过程都是在计算Ack和Seq的值,保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成。
  这里引用一个动态图:

  这就是 “三次握手”的过程。
  粉丝A:你好,我是你的粉丝A,很高兴认识你
鸟哥:
鸟哥一直进入答疑,然而这是恶作剧,并没有人问。
问题1:两次握手可以吗?
  1)第一次握手


[*]第一次握手的时候,客户端发送 SYN 包之后,切换到 SYN 状态,这个和三次握手中的第一次是一样的。
  2)第二次握手


[*]假设只有两次握手,那么服务端在获得 SYN 包之后就会进入到 ESTABLISHED 状态(请注意,这里服务端比客户端提前进入了ESTABLISHED状态,ESTABLISHED状态下会请求跟数据传输阶段有关的内存消耗,然后等待数据通信)
[*]然后,回复给客户端SYN+ACK包,表示我收到了你的连接请求。
  这里就是我们讨论的点:

[*]  正常网络和用户请求(也就是每个请求都不需要重发,每个请求都是正常请求)的前提下,两次握手是足够,省了一次。

[*]  假设此时有网络延迟问题,客户端连续发送两个 SYN 包,是不是意味着 服务端会建立两个连接?来者不拒。(当然有人就说了,我是不是可以判断两次的SYN包呢,丢弃第二次。但是 我一个 ESTABLISHED 状态的 服务连接为什么还要消耗资源去处理 SYN 上的包呢?这个是我们需要考虑的地方)。
[*]  假设网络是好的,根据来者不拒的原则,此时有个***想***我们的网络,不断发送 SYN 包,是不是意味着 我们服务端需要不断建立非常庞大的无效连接(每个连接都需要消耗内存资源)
[*]  对标场景:
  恶作剧A:你好,我是你的粉丝A,很高兴认识你,鸟哥立马进入答疑
恶作剧B:你好,我是你的粉丝B,很高兴认识你,鸟哥立马进入答疑

鸟哥一直进入答疑,然而这是恶作剧,并没有人问,浪费鸟哥时间。
  两次握手的情况下,服务端比客户端更快进入了ESTABLISHED 状态,从资源消耗的角度来看,非常不合理(其实就跟手机用户访问网站一样,网站资源是非常珍贵的,反而是手机资源属于用户级别,浪费的只是自己的手机资源)。
  结论:

[*]两次握手导致服务端优先进入了 ESTABLISHED 状态,提前消耗了连接资源。
[*]在普通情况(不存在网络***)下,客户端优先进入到 ESTABLISHED 状态,也是属于主动请求的一种表现,服务端收到ACK包之后才考虑消耗自己的资源,达到C-S的状态同步。
问题2:三次握手就可以了吗?是否考虑4次?
  在不考虑网络***的情况下,三次握手已经满足了我们的要求,但是仍然解决不了网络***的问题。那么4次握手能解决网络***吗?
4次握手,其实就是形成了一个环形结构。从哪里来,回到哪里去。

这里你会发现,就算多一次,仍然解决不了,因为客户端可以伪装发送ACK,服务端一样会进入到 ESTABLISHED 状态。而且4次握手,白白浪费了一次传输时间 MSL。
3.2.2 断开释放连接阶段(四次挥手拜拜)
  四次挥手即TCP连接的释放(解除):



  1)第一次握手,客户端提出释放连接,发送 FIN(Seq = U),然后进入FIN-WAIT-1,也就是半关闭状态。停止客户端向服务端发送数据,但是客户端仍然能接收服务端传输过来的数据。(客户端从 ESTABLISHED 状态 变更为 FIN-WAIT-1 状态)
  2)第二次握手服务端收到客户端的FIN 包后,知道了客户端想要释放连接,随后服务端从 ESTABLISHED 状态 切换到 CLOSE- WAIT 状态,并且返回一个 ACK 包(Seq=V,Ack=U+1)给 客户端。记住,这个时候服务端可能还没有完全接收完客户端的数据(网络延迟),还在继续接收数据。客户端收到 ACK包之后,会进入到 FIN-WAIT-2状态.
  3)第三次握手,当服务端确收完了所有数据,就会给客户端发送 FIN (Seq=w,Ack=U+1)包,表示我真的接收完数据了,此时会从 CLOSE-WAIT状态切换到 LAST-ACK状态。
  4)第四次握手,当客户端收到 FIN 包之后,会给服务端也发送一个 ACK 包(Seq = U+1,ack=w+1),同时给双方一个认真考虑是否真的释放连接关系的时间(考虑时间为2MSL,也就是一个网络来回的时间,也就是发送一个ACK包和FIN包的时间,刚好够服务端再次发送一个FIN包)。在考虑时间内,如果没有再次收到 FIN包,客户端就认为 服务端收到了 ACK 包,我们的关系到此结束。

业务场景:
  …(省略好多字的交流)
粉丝A:我的整个问题问完了,谢谢鸟哥
鸟哥:没事,谢谢灵通
鸟哥:还有其他问题吗?
粉丝A:没有了,谢谢。

4.总结
  源于与同事的互水讨论,更加对 TCP协议中的三次握手和四次挥手有更深刻的理解,在此谢谢大佬。
  

  
页: [1]
查看完整版本: TCP协议中的三次握手和四次挥手,一个同同事互水的技术话题(经典面试题目)