当前位置: 首页 > ai >正文

为什么TCP连接是三次握手?不是四次两次?

  1. 第一次握手(A -> B): A 对 B 说:“喂,你能听到我说话吗?我想和你通话。” (A 发送 SYN 包)
  2. 第二次握手(B -> A): B 听到后,回复 A 说:“我听到了,我也能说话,你听到我说话了吗?” (B 发送 SYN+ACK 包)
  3. 第三次握手(A -> B): A 听到 B 的回复后,对 B 说:“我听到了,我们都准备好了,开始通话吧!” (A 发送 ACK 包)

通过这三步,双方都确认了对方能发能收,并且自己也能发能收,这样就可以放心地开始传输数据了。

为什么需要三次握手?

要理解三次握手,我们得先从 TCP 的“宏观目标”和“微观步骤”来思考。

TCP(传输控制协议)的核心目标是提供可靠的、面向连接的、基于字节流的传输服务。这里的“可靠”是关键。在网络这个充满不确定性的世界里,数据包可能会丢失、延迟、重复,甚至乱序。TCP 必须确保发送的数据最终能完整、正确地到达接收方。

为了实现“可靠”,TCP 在数据传输前,需要建立一个“连接”。这个连接就像一条虚拟的管道,确保双方都准备好发送和接收数据。三次握手就是建立这条管道的关键步骤。

我们来模拟一下,如果没有三次握手,会发生什么?

场景一:只有两次握手(A -> B, B -> A)

假设只有两次握手:

  1. A 发送连接请求(SYN)。
  2. B 收到请求,回复确认(SYN+ACK),并认为连接已建立,可以发送数据。

问题: 如果 A 发送的第一个 SYN 包在网络中丢失了,或者延迟了很久才到达 B。

  • 如果丢失了,A 会重发 SYN,B 收到后建立连接。但如果 B 的 SYN+ACK 也丢失了,A 永远不知道连接是否建立。
  • 如果延迟了很久,A 可能会因为超时而重发 SYN。B 收到第一个延迟的 SYN 后,会回复 SYN+ACK,并认为连接建立。但此时 A 可能已经放弃了这次连接,或者已经和 B 建立了新的连接。这样 B 就会白白等待,甚至发送数据,造成资源浪费和逻辑混乱。

核心问题: 两次握手无法确保**客户端(A)能够收到服务器(B)的确认,也无法确保服务器(B)能够确认客户端(A)**已经收到了自己的确认。换句话说,B 无法确认 A 是否真的准备好接收数据。

场景二:三次握手

  1. 第一次握手 (SYN): 客户端 A 发送一个 SYN 包给服务器 B,并进入 SYN_SENT 状态。
    • 目的: A 告诉 B:“我想和你建立连接,我能发送数据。”
    • A 的视角: 我发出了请求,等待 B 的回应。
    • B 的视角: 我收到了 A 的请求,知道 A 想和我建立连接。
  2. 第二次握手 (SYN+ACK): 服务器 B 收到 SYN 包后,回复一个 SYN+ACK 包给客户端 A,并进入 SYN_RCVD 状态。
    • 目的: B 告诉 A:“我收到了你的请求,我也同意建立连接,我也能发送数据,你收到我的回复了吗?”
    • A 的视角: 我收到了 B 的回应,知道 B 愿意建立连接,并且 B 也能发送数据。
    • B 的视角: 我发出了回应,等待 A 的确认。
  3. 第三次握手 (ACK): 客户端 A 收到 SYN+ACK 包后,回复一个 ACK 包给服务器 B,并进入 ESTABLISHED 状态。
    • 目的: A 告诉 B:“我收到了你的确认,我知道你准备好了,我们都准备好了,可以开始传输数据了。”
    • A 的视角: 我已经确认 B 准备好了,我也准备好了,连接建立。
    • B 的视角: 我收到了 A 的最终确认,知道 A 也准备好了,连接建立。

为什么三次握手是“最少”的?

  • 第一次握手: 客户端 A 告诉服务器 B,A 能够发送数据。
  • 第二次握手: 服务器 B 告诉客户端 A,B 能够发送数据,并且 B 已经收到了 A 的发送能力确认。
  • 第三次握手: 客户端 A 告诉服务器 B,A 已经收到了 B 的发送能力确认。

通过这三步,双方都互相确认了对方的发送能力和自己的接收能力

  • A 确认了:B 能发,B 能收。
  • B 确认了:A 能发,A 能收。

如果只有两次握手,B 无法确认 A 是否收到了自己的 SYN+ACK,也就无法确认 A 是否真的准备好接收数据。第三次握手就是为了解决这个“B 无法确认 A 是否收到”的问题。

思考:

  • “已失效的连接请求报文段”问题: 假设客户端 A 发送了一个连接请求 SYN,但这个 SYN 包在网络中滞留了很久。A 等待超时后,会重发 SYN,并成功与服务器 B 建立了连接,传输了数据,然后关闭了连接。

    • 此时,那个滞留的旧 SYN 包终于到达了 B。B 收到后,会认为 A 又要建立连接,于是回复 SYN+ACK。
    • 如果只有两次握手,B 就会认为连接建立,并等待 A 发送数据。但 A 根本没有发送这个旧的 SYN,也不会理会 B 的 SYN+ACK。B 就会白白等待,浪费资源。
    • 有了第三次握手,A 收到 B 的 SYN+ACK 后,会发现这个 SYN+ACK 对应的序列号是旧的,或者根本不是自己当前发出的连接请求,A 会发送 RST(复位)包给 B,告诉 B 这个连接请求是无效的,从而避免了资源的浪费。
  • 四次挥手: 为什么断开连接需要四次挥手而不是三次?

    • 因为 TCP 是全双工的,数据可以双向流动。
    • 当一方(比如客户端)说“我没数据要发了”,它只是关闭了自己发送数据的通道。但服务器可能还有数据要发送给客户端。
    • 所以,服务器收到客户端的关闭请求后,会先回复一个 ACK,表示“我知道你要关闭了”。然后,服务器会继续发送它剩余的数据。
    • 等服务器也把数据发完了,它才会再发送一个 FIN 包,表示“我也没数据要发了,你可以关闭了”。
    • 客户端收到 FIN 后,再回复一个 ACK。
    • 这就像两个人打电话,一个人说“我没话说了”,另一个人说“好的,我知道了,但我还有几句话要说”,等他说完,再说“好了,我说完了,你可以挂电话了”,对方再回复“好的,我挂了”。

TCP 三次握手的状态变迁

graph TDA[客户端: CLOSED] --> B{客户端发送 SYN<br/>seq=x};B --> C[客户端: SYN_SENT];D[服务器: CLOSED] --> E[服务器: LISTEN];C -- SYN (seq=x) --> E;E -- SYN+ACK (seq=y, ack=x+1) --> C;F[服务器: SYN_RCVD];E --> F;C -- ACK (ack=y+1) --> F;G[客户端: ESTABLISHED];C --> G;H[服务器: ESTABLISHED];F --> H;G -- 数据传输 --> H;
  • 客户端:
    • CLOSED:初始状态,什么都没做。
    • SYN_SENT:发送了 SYN 包,等待服务器的 SYN+ACK。
    • ESTABLISHED:收到服务器的 SYN+ACK 后,发送 ACK,并进入此状态,表示连接已建立,可以开始数据传输。
  • 服务器:
    • CLOSED:初始状态。
    • LISTEN:服务器启动,开始监听客户端的连接请求。
    • SYN_RCVD:收到客户端的 SYN 包后,发送 SYN+ACK,等待客户端的 ACK。
    • ESTABLISHED:收到客户端的 ACK 后,进入此状态,表示连接已建立,可以开始数据传输。

TCP 三次握手是建立可靠连接的关键机制,它通过三次消息交换,确保了通信双方都能发送和接收数据,并且都确认了对方的收发能力。

  1. 第一次握手(SYN): 客户端发送一个 SYN(同步序列号)包到服务器,并选择一个初始序列号 seq=x。这表示客户端请求建立连接,并告知服务器自己将从序列号 x 开始发送数据。客户端进入 SYN_SENT 状态。
  2. 第二次握手(SYN+ACK): 服务器收到客户端的 SYN 包后,如果同意建立连接,会发送一个 SYN+ACK(同步确认)包。这个包包含:
    • SYN:服务器也选择一个初始序列号 seq=y,表示自己将从序列号 y 开始发送数据。
    • ACK:确认号 ack=x+1,表示服务器已经成功接收到客户端的 SYN 包,并期望客户端下一个数据包的序列号是 x+1
      服务器进入 SYN_RCVD 状态。
  3. 第三次握手(ACK): 客户端收到服务器的 SYN+ACK 包后,会发送一个 ACK(确认)包。这个包包含:
    • ACK:确认号 ack=y+1,表示客户端已经成功接收到服务器的 SYN 包,并期望服务器下一个数据包的序列号是 y+1
      客户端发送此 ACK 包后,立即进入 ESTABLISHED 状态。服务器收到此 ACK 包后,也进入 ESTABLISHED 状态。
http://www.xdnf.cn/news/18023.html

相关文章:

  • ruoyi-vue(十一)——代码生成
  • ansible管理变量和事实
  • Chrome插件开发实战:todoList 插件
  • 影刀初级B级考试大题2
  • Java ArraysParallelSortHelpers 并行排序
  • PyTorch 面试题及详细答案120题(01-05)-- 基础概念与安装
  • 深度学习-计算机视觉-数据增广/图像增广
  • AMBA-AXI and ACE协议详解(三)
  • TDengine IDMP 运维指南(1. 部署规划)
  • 基于飞算JavaAI的可视化数据分析集成系统项目实践:从需求到落地的全流程解析
  • 学习游戏制作记录(玩家掉落系统,删除物品功能和独特物品)8.17
  • Vue深入组件:Props 详解2
  • LINUX学习笔记
  • [RCTF2015]EasySQL
  • 11.苹果ios逆向-FridaHook-ios中的算法-CC_SHA1(sha1算法)
  • maxwell安装部署
  • 裸机框架:按键模组
  • PCA 实现多向量压缩:首个主成分的深层意义
  • 网络通信的基本概念与设备
  • 链路聚合与软件网桥
  • Android面试指南(二)
  • 记SpringBoot3.x + Thymeleaf 项目实现(MVC架构模式)
  • 校园综合数据分析可视化大屏 -Vue纯前端静态页面项目
  • Ugit使用记录
  • Git 入门指南:核心概念与常用命令全解析
  • Docker-14.项目部署-DockerCompose
  • 【Jenkins】02 - 自动化部署配置
  • 【Linux系列】如何在 Linux 服务器上快速获取公网
  • PAT 1068 Find More Coins
  • 补充:用信号量实现前驱关系