基于本文回答

播面 播面

文图音视,全方位拆解八股文
0
评论

TCP的三次握手

知识点图片

本文讲解TCP三次握手:一个为建立可靠连接而设计的双向确认过程。客户端发起请求(SYN),服务器响应确认和请求(SYN-ACK),最后客户端再次确认(ACK)。此过程确保双方收发正常,并防止失效连接请求。

我们来详细、通俗地讲解一下TCP的三次握手(Three-way Handshake)原理。

一、一句话比喻:打电话

想象一下你和朋友打电话的过程,这个过程和三次握手非常相似:

  1. 第一次握手(你打给朋友)

    • :“喂,能听到我说话吗?”
    • 你的目的:确认朋友能收到你的信息。
  2. 第二次握手(朋友回应你)

    • 朋友:“我听到了。你能听到我说话吗?”
    • 朋友的目的:1. 告诉你他听到了(回应你的请求)。 2. 问你是否能听到他说话(发起自己的请求)。
  3. 第三次握手(你再次回应朋友)

    • :“我也能听到你。好了,我们可以开始聊天了。”
    • 你的目的:告诉朋友你收到了他的信息,现在双方都确认通信线路是通畅的。

经过这三步,双方都确认了自己和对方的发送接收能力都是正常的,然后才能开始真正地通话。TCP三次握手就是为了在网络中建立这样一个可靠的双向通信信道。


二、三次握手的核心目的

TCP是一种可靠的、面向连接的传输协议。在正式传输数据之前,必须先建立一个可靠的连接。三次握手的核心目的主要有三个:

  1. 确认双方的收发能力:确保客户端(Client)和服务器(Server)都能正常发送和接收数据。
  2. 同步初始序列号(ISN, Initial Sequence Number):TCP会为每个发送的字节分配一个序列号(Sequence Number, SEQ),以保证数据的有序和不重复。握手过程就是为了协商和同步双方的初始序列号。
  3. 防止已失效的连接请求:避免因为网络延迟等原因,导致早已失效的连接请求突然到达服务器,从而错误地建立连接,浪费服务器资源。

三、技术细节:三次握手的详细过程

在TCP协议中,数据包的头部有几个非常重要的标志位(Flags),在握手过程中主要用到两个:

  • SYN (Synchronize):同步标志位。当SYN=1时,表示这是一个请求建立连接的报文。
  • ACK (Acknowledge):确认标志位。当ACK=1时,表示这是一个确认报文,此时确认号(Acknowledgement Number)字段才有效。

此外,还有两个关键的数字:

  • 序列号 (Sequence Number, seq):我方发送的数据的初始编号。
  • 确认号 (Acknowledgement Number, ack):我方期望下次收到的、对方数据的编号。

下面是三次握手的具体步骤(假设客户端主动发起连接):

第一次握手(Client -> Server)

  • 状态:客户端处于 CLOSED 状态,服务器处于 LISTEN 状态。
  • 客户端操作
    1. 客户端随机选择一个初始序列号 seq = x
    2. 将TCP报文的标志位 SYN 设置为 1
    3. 将报文发送给服务器。
  • 报文内容SYN = 1, seq = x
  • 客户端状态变化:发送后,客户端进入 SYN_SENT(同步已发送)状态,等待服务器确认。

通俗解释:客户端对服务器说:“你好,我想和你建立连接,我的初始序列号是 x,你收到了吗?”

第二次握手(Server -> Client)

  • 服务器操作
    1. 服务器收到客户端的SYN报文后,也随机选择一个自己的初始序列号 seq = y
    2. 为了确认已收到客户端的报文,服务器将确认号设置为 ack = x + 1。(表示“我收到了你的序列号x,我希望你下一个发来的数据从x+1开始”)。
    3. 将TCP报文的标志位 SYNACK 都设置为 1
    4. 将报文发送给客户端。
  • 报文内容SYN = 1, ACK = 1, seq = y, ack = x + 1
  • 服务器状态变化:发送后,服务器进入 SYN_RCVD(同步已接收)状态。

通俗解释:服务器对客户端说:“我收到你的请求了(确认号是x+1)。我也想和你建立连接,我的初始序列号是 y,你收到了吗?”

第三次握手(Client -> Server)

  • 客户端操作
    1. 客户端收到服务器的 SYN+ACK 报文后,检查确认号 ack 是否为 x + 1。如果正确,则表示到服务器的通路是正常的。
    2. 为了确认已收到服务器的报文,客户端将确认号设置为 ack = y + 1。(表示“我收到了你的序列号y,我希望你下一个发来的数据从y+1开始”)。
    3. 将TCP报文的标志位 ACK 设置为 1
    4. 将自己的序列号设置为 seq = x + 1
    5. 将报文发送给服务器。
  • 报文内容ACK = 1, seq = x + 1, ack = y + 1
  • 双方状态变化
    • 客户端发送后,进入 ESTABLISHED(连接已建立)状态,此时可以开始发送数据。
    • 服务器收到客户端的ACK报文后,也进入 ESTABLISHED 状态,连接建立成功。

通俗解释:客户端对服务器说:“我收到你的确认和请求了(确认号是y+1),现在我们可以开始通信了。”

至此,三次握手完成,双方都进入了 ESTABLISHED 状态,可以进行双向数据传输。


四、为什么是三次,而不是两次或四次?

这是一个经典的面试问题。

为什么不能是两次握手?

主要原因是为了防止已失效的连接请求报文突然又传送到了服务器

  • 场景:客户端发送了一个SYN请求(我们称之为 SYN_old),但因为网络拥堵,这个请求很久都没有到达服务器。
  • 客户端行为:客户端等了一段时间后,发现没有回应,于是重新发送了一个新的SYN请求(SYN_new)。
  • 正常流程SYN_new 正常到达服务器,服务器回复,双方通过两次握手(假设)建立了连接,然后传输数据,最后关闭连接。
  • 问题出现:此时,那个在网络中滞留的 SYN_old 终于到达了服务器。
    • 如果是两次握手:服务器收到 SYN_old 后,会误以为这是一个新的连接请求。它会立即向客户端发送确认报文,并分配资源,进入 ESTABLISHED 状态。但此时客户端实际上处于关闭状态,不会理会这个确认。结果就是,服务器单方面建立了一个“半开连接”(Half-Open Connection),并一直等待一个永远不会来的客户端数据,造成了资源浪费。
    • 如果是三次握手:服务器收到 SYN_old 后,会回复一个 SYN+ACK 报文。但客户端发现这个报文的序列号对不上(或者它根本就不想建立连接),就不会发送第三次握手的ACK。服务器收不到这个ACK,就知道客户端并不想建立连接,于是就不会进入 ESTABLISHED 状态,也就避免了资源浪费。

简单来说,第三次握手是让服务器确认“客户端确实收到了我的回复,并且真的准备好了建立连接”。

为什么不需要是四次握手?

因为服务器在第二次握手中,将自己的 SYN 请求和对客户端的 ACK 确认,合并在一个报文中发送了 (SYN+ACK)。这完全可以满足需求,并且比分开发送(先发ACK,再发SYN)更高效。所以,没有必要进行四次握手。

总结

TCP三次握手是一个精心设计的过程,它通过三次信息交换,确保了通信双方都具备可靠的收发能力,并同步了各自的初始序列号,最终建立起一个全双工的、可靠的通信通道。它既保证了连接的可靠性,又兼顾了效率。

00:00
00:00