tcp握手为什么是三次不是两次_tcp的三次握手

tcp握手为什么是三次不是两次_tcp的三次握手TCP采用三次握手的原因其实非常简单,远没有大部分博客所描述的那样云山雾绕。

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

参考文章

Why do we need a 3-way handshake? Why not just 2-way

大部分网络博客的错误解读

首先需要声明的是, 百度搜索到的大部分网络博客关于这个问题的解答都是不清晰或者不准确的。 讨论这个问题的大部分博客都会引用《计算机网络》的内容:

  1. 防止已失效的连接请求又传送到服务器端,因而产生错误

不幸的是, 这种解释是不准确的, TCP 采用三次握手的原因其实非常简单, 远没有大部分博客所描述的那样云山雾绕。

这里先给出结论:

  • 为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤
  • 如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认

先修知识

TCP 通信流程

TCP 的通信流程
在这里插入图片描述

上图中的每一个箭头都代表着一次 TCP数据包的发送

  • 需要注意的是, 上图中出现的 ACK = x +1 的写法很容易让人误以为数据包中的 ACK 域的数据值被填成了 y+1 。 ACK = x+1 的实际含义是:
    • TCP 包的 ACK 标志位(1 bit) 被置成了 1
    • TCP 包的确认号(acknowledgement number ) 的值为 x+1
  • 类似的, TCP 数据包中的 SYN 标志位, 也容易与序号(sequence number) 混淆, 这点需要读者注意

TCP 数据包结构图
TCP包结构图

为什么 TCP 需要握手这个操作

在解答为什么 TCP 需要三次握手, 而不是两次之前, 首先需要回答的问题是:

  • 为什么需要握手这个操作, 能不能不握手?

如果读者对比一下 UDP 的通信流程和 TCP 的通信流程, 可以发现, 在 UDP 协议中, 是没有握手这个操作的。
在这里插入图片描述

这里就引出了 TCP 与 UDP 的一个基本区别, TCP 是可靠通信协议, 而 UDP 是不可靠通信协议。

  • TCP 的可靠性含义: 接收方收到的数据是完整, 有序, 无差错的。
  • UDP 不可靠性含义: 接收方接收到的数据可能存在部分丢失, 顺序也不一定能保证。

UDP 和 TCP 协议都是基于同样的互联网基础设施, 且都基于 IP 协议实现, 互联网基础设施中对于数据包的发送过程是会发生丢包现象的, 为什么 TCP 就可以实现可靠传输, 而 UDP 不行?

TCP 协议为了实现可靠传输, 通信双方需要判断自己已经发送的数据包是否都被接收方收到, 如果没收到, 就需要重发。 为了实现这个需求, 很自然地就会引出序号(sequence number)确认号(acknowledgement number) 的使用。

发送方在发送数据包(假设大小为 10 byte)时, 同时送上一个序号( 假设为 500),那么接收方收到这个数据包以后, 就可以回复一个确认号(510 = 500 + 10) 告诉发送方 “我已经收到了你的数据包, 你可以发送下一个数据包, 序号从 510 开始” 。

这样发送方就可以知道哪些数据被接收到,哪些数据没被接收到, 需要重发。

为什么需要三次握手,而非两次

正如上文所描述的,为了实现可靠传输,发送方和接收方始终需要同步( SYNchronize )序号。 需要注意的是, 序号并不是从 0 开始的, 而是由发送方随机选择的初始序列号 ( Initial Sequence Number, ISN )开始 。 由于 TCP 是一个双向通信协议, 通信双方都有能力发送信息, 并接收响应。 因此, 通信双方都需要随机产生一个初始的序列号, 并且把这个起始值告诉对方。

于是, 这个过程就变成了下面这样。
在这里插入图片描述

下面这个流程图描述的和上面一样, 但是更加清楚的展示了 TCP 数据包标志位, 以及数据域的命名来源。

Alice Bob SYN =1 , seq = x SYNchronize with my Initial Sequence Number of x SYN =1, ACK = 1, seq = y , ack = x+1 I received your ISN, I ACKnowledge that I am ready for [x+1] SYNchronize with my Initial Sequence Number of y ACK =1 , seq = x+1, ack = y+1 I received your syn, I ACKnowledge that I am ready for [y+1] Alice Bob

题外话

有一位读者关注到了三次握手中, 序列号变化的问题, 让笔者临时想起了曾经困扰自己的一个问题

  • 为什么三次握手最后一次握手中, 在上面的示意图中回复的 seq = x+1 。

答案: (此处感谢 “楚天千里清秋” 的提醒, 进行了修正)

acknowledgement number 的作用是向对方表示,我期待收到的下一个序号。 如果你向对方回复了 ack = 31, 代表着你已经收到了序号截止到30的数据,期待的下一个数据起点是 31 。

TCP 协议规定SYN报文虽然不携带数据, 但是也要消耗1个序列号, 所以前两次握手客户端和服务端都需要向对方回复 x+1 或 y+1 。

在这里插入图片描述
在这里插入图片描述
值得注意的是, 如上图所说, 最后一次握手在默认不携带数据的情况下, 由于SYN 不是 1 , 是不消耗序列号的。 所以三次握手结束后, 客户端下一个发送的报文中 seq 依旧是 x+1, 示意图如下

在这里插入图片描述
注意到, 上图第四步发送的 seq 和第三次握手的 seq 是一样的, 体现了最后一次握手, 默认不消耗序列号的特点。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/188074.html原文链接:https://javaforall.net

(0)
上一篇 2026年4月17日 下午6:13
下一篇 2026年4月17日 下午6:19


相关推荐

  • 算数平均数与几何平均数

    算数平均数与几何平均数算数平均数与几何平均数文章目录算数平均数与几何平均数一 算数平均数二 几何平均数 1 定义 2 几何意义三 二者关系一 算数平均数算数平均数分为简单算数平均数与加权算术平均数 简单算术平均 主要用于未分组的原始数据 设一组数据为 x1x 1×1 x2x 2×2 x3x 3×3 xkx kxk 得到简单算数平均 M x1 x2 x3 xkkM frac x 1 x 2 x 3 x k k M kx1 x2 x3 xk 加权算术平均 主要用于处理经分组整理的

    2026年3月19日
    2
  • 有效避免JS全局变量污染

    有效避免JS全局变量污染1、使用名称空间varA={};//必须定义为对象A.person={name:"zhangsan",age:18,body:{height:"180cm",weight:"70kg"}};//var定义的全局不能被删除//deleteA;//隐式全局变量被删除//deleteA.p…

    2022年5月9日
    41
  • freopen用法

    freopen用法在做 acm 题目的过程中 我们需要在本地机器上调试 调试过程中 如果输入数据少还可以接受 但如果输入数据很庞大的话 我们就很难忍受一次又一次的重新输入和调试了 通过 google 找到一种简便的方法 那就是 freopen 函数 nbsp nbsp nbsp nbsp nbsp nbsp nbsp 使用 freopen 函数可以解决测试数据输入问题 避免重复输入 不失为一种简单而有效的解决方法 nbsp nbsp nbsp nbsp 下面为函数的简介 详细可参见 nbsp http www

    2026年3月3日
    1
  • Docker Compose搭建mycat读写分离

    Docker Compose搭建mycat读写分离接上篇docker-compose部署mysql主从复制,本文介绍如何搭建mycat中间件,并用mycat来做读写分离.配置文件以及文档地址:mycat-rw系统环境docker1.12.3mysql5.7.17deepin15.3桌面版(这个没啥影响,因为我们用docker)mycat1.6要点说明看上篇文章的详细介绍暴露mysqlmycat端口号,方便管理本文直接从dock

    2022年10月10日
    3
  • DWARF调试格式的简介

    DWARF调试格式的简介https blog csdn net wuhui gdnt article details DWARF 调试格式的简介 MichaelJ Eager EagerConsult 2007 翻译 吴晖 2012 年 2 月如果我们可以编写确保能正确工作且永远不需要调试的程序 这将非常美妙 在梦想成真之前 通常的编程周期还将是包括 编写一个程序 编译它

    2026年3月19日
    2
  • 20 分钟拥有 24/7 AI 私人助理:OpenClaw 从零部署完全指南

    20 分钟拥有 24/7 AI 私人助理:OpenClaw 从零部署完全指南

    2026年3月15日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号