TCP --- 确认应答机制以及三次握手四次挥手
序言
在前一篇文章中,我们介绍了 UDP协议 (点击查看)👈,该协议给我们的感觉就两个字 — 简单,只是将我们的数据进行简单的添加报头然后发送。当然使用起来虽然简单,但是否能送到目的地,那就要看网络的状态了以及一些随机成分了。
今天介绍的 TCP 比起前者的原理要复杂很多,但是正是因为这个缜密的设计才能让我们的通信更加的稳定!
TCP 协议段格
光是看该协议段格式的设计就比 UDP 丰富许多:

字段很多,我们在这里只是简单的介绍不过多的阐述,在后面讲述功能时会将对应的字段进行详细的介绍。
头两个字段,源端口,目的端口 也就是表示数据是从哪个进程来,到哪个进程去,这在 UDP 中出现过。现在介绍我们之前没见过的:
-
序列号:TCP 会将数据较大的数据包进行分段处理后再发送,序号
用于标识数据段的顺序,确保数据按顺序到达接收方。 -
确认应答号:用于确认已接收到的数据,确保数据的可靠传输。确认号的值表示接收方期望收到的下一个数据段的序号。
-
首部长度:表示 TCP 报头的长度,单位是 4 字节。这代表 TCP 长度的最大值为 60 字节。
-
窗口大小:通过滑动窗口来控制流量,后面会详细介绍。
-
6 个标志位:
–URG: 紧急指针是否有效
–ACK: 应答标记位
–PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走
–RST: 对方要求重新建立连接
–SYN: 请求建立连接
–FIN: 断开连接 -
校验和,紧急指针,选项:本篇文章不提及。
确认应答机制
1. 基本原理
灵感来源于生活!举个简单的例子:你正在厨房里做饭,你的孩子正在房间里愉快的开黑。饭做好了,你朝着房间说:吃饭了!吃饭了!你的孩子收到了,说了一声:好的!我来啦!但是如果房间里没有任何的回应呢?那你肯定再次重复,直到你的孩子听见了,对你有了答复。
所以怎么保证对方收到了你的消息呢?给你应答!确认应答机制就是这样:当接收方成功接收到发送方发送的数据段后,它会向发送方发送一个 ACK 报文,以确认该数据段已被成功接收。
2. 基本流程
发送方将要发送的数据 每个字节的数据都进行了编号.即为序列号:

然后,发送方将这些数据段依次发送给接收方。
就比如,发送端现在一共将数据分成了三段,每一段的序列号分别是:1000,2000,3000。接收端收到序列号为 1000 的数据包时,会发送一个应答报文(ACK 置 1),表示收到该段数据。那么,该确认应答号应该是 1000 咯。
不是的!确认应答号 = 接受的序列号 + 1,表示 收到该确认序列号之前的数据,期望的收到的下一个数据段的开始。 为什么要这样设计呢?允许少量的应答报文丢失。如果我们使用的第一种方式,那么我们必须保证收到该序列号报文对应的 ACK 报文,没收到就认为是丢失,需要补发!但是我们采取第二种方式,比如现在一共发了六个数据包,就算前面的丢失了,但是只要返回了第六个的应答报文,那么就意味着六个都到了!
重传机制
在网络中传输数据,免不了会遇到数据丢失的情况,那么 TCP 遭遇这种情况时,是怎么处理的呢?
1. 超时重传
主机 A 向 主机B 发送了一段数据,但是 A 迟迟没有接收到来自 B 的应答报文。会是什么原因呢?
- 主机 A 的发送的数据包丢失了或阻塞了
- 主机 B 的应答报文丢失了或阻塞了
主机 A 肯定不知道原因是什么,他只会补发数据直到收到应答报文!那么什么时候 A 会去补发数据呢:

首先这个时间间隔肯定不是固定的!因为网络情况是波动的,当网络延迟高的时候,时间肯定短一点,及时的去补发数据;当网络延迟低的时候,时间肯定长一点,避免频繁发送重复的包。
具体的步骤是,起始的时间间隔为 500ms,如果重发一次之后,仍然得不到应答,等待 2*500ms 后再进行重传。如果仍然得不到应答, 等待 4*500ms 进行重传。类推,累计到一定的重传次数,TCP 认为网络或者对端主机出现异常,强制关闭连接。
2. 快重传
比如现在我们一共有 10 个数据段,序号分别是 1000,2000,… ,10000, 现在发送端将数据全部发送,除了 2000 都到了接收端,那么接收端是如何返回应答报文的呢:

为什么返回的应答报文的确认应答号都是 1001 呢?在之前说了,确认应答号代表该号数之前的数据已经被接受! 就拿序列号为 5000 的来说,该序列号对应的报文确实已经被收到了,但是他之前的报文还缺一个 2000(1001 ~ 2000),所以只能是返回 1001。
当发送端接收到 连续的3个重复确认,它会立即重新发送丢失的数据段,而不需要等待超时时间到期。
TCP 的确认应答机制通过发送 ACK报文、引入重传机制和序列号管理等方式,确保了数据的可靠传输。这一机制在 TCP 协议中起着至关重要的作用,为网络通信的可靠性和稳定性提供了有力保障。
连接管理
在这里的连接管理,实际上就是我们常听到的三次握手建立连接,四次挥手断开连接的过程。
1. 三次握手
首先,我们来分析一下三次握手的过程:

- 客户端发送
SYN报文,想要和服务端建立连接,进入SYN_SENT状态 - 服务端接收到请求后表示同意,并且也表示想要建立连接,进入
SYN_RCVD状态 - 客户端收到报文后,回应最后一个
ACK报文,进入ESTABLISHED状态 - 服务器收到应答后,也进入
ESTABLISHED状态
在这里我们首先解决几个前面没有介绍的知识点:
- 标记位报文:在这里我们提到发送
SYN报文(表示建立连接),但是SYN只是一个标记位呀?没关系的,我们只需要将该标记位置 1
,数据字段不填就是了。常见的还有:ACK报文(表示应答对应的数据),FIN(请求断开连接)…- 捎带标记位:比如当 A 向主机 B 发送数据后,B 肯定需要发送应答报文,但是此时恰巧 B 也有向 A 发送的数据,那么就可以将该数据和应答合并发送(两者并不会冲突,因为应答只需要将标记位
ACK置 1 即可),不需要单独发送一个仅包含
ACK的包,从而减少网络上的数据包数量
好的了解三次握手建立连接的步骤后,我们提出以下问题:
- 为什么是三次,不是四次,五次?
- 如果第一次握手请求丢失会怎么样?
- 如果第二次握手请求丢失会怎么样?
- 如果第三次握手请求丢失会怎么样?
问题只会帮助我们更好的理解知识,现在我们一个一个的来解释一下:
问题一:
保证双方具有发送和接受信息的能力:在这三次握手中,发送端发送了一次数据(最开始的SYN报文),接受了一次数据(ACK + SYN);接收端接受了一次数据(最开始的SYN报文),发送了一次数据(ACK + SYN)。三次握手以最小的成本保证双方具有接收和发送的能力! 你四次(如果将中间的捎带应答分开,分两次发,也就是四次应答!)五次都行,但是没必要!- 初始化并同步序列号:接收端和发送端根据序列号来标识每个传输的数据包,确保数据的顺序性和完整性。你想一下,如果你在第一次发了一个数据包但是在网络上阻塞了,数据迟迟没到,你断开了连接;过了一会你重新建立连接,再次发送数据,好巧不巧第一次在网络上阻塞的数据也到了接收端,如果接收端接受了那么肯定数据就错乱了!为了避免这种情况,
每次建立连接时,双方都会生成一个新的初始序列号,这是为了确保通信的可靠性和安全性。 - 避免历史连接:在这里我们引入一个实际的场景:

原来存在一个历史的连接请求阻塞在网络中,现在客户端发起一个新的连接请求,但是历史的请求也到达了服务端。如果没有中间那次服务端的确认,那么在两次握手后服务端就成功进入ESTABLISHED状态。如果服务端向客户端发送相应的数据,这不是妥妥浪费资源吗?所以,我们需要一个中间状态来确认对方的身份,阻止历史连接造成资源的浪费!
问题二:
如果第一次链接请求都丢失了,那么则会触发前面说到的 超时重传。
问题三:
- 对于客户端来说,我没有收到你的
ACK,那么是不是我的请求没有送到呢?于是会触发超时重传 - 对于服务端来说,我的信息都发出这么久了咋还不回我,触发
超时重传
两者都会触发 超时重传 ,因为在网络上确认对方收到自己信息的唯一方式就是收到相应的应答,没收到应答,我就认为你没有收到我的信息!
问题四:
因为这个第三次握手的 ACK 是对第二次握手的 SYN 的确认报文,所以当第三次握手丢失了,如果服务端那一方迟迟收不到这个确认报文,就会触发超时重传机制,重传 SYN-ACK 报文,直到收到第三次握手或者达到最大重传次数。
这就是三次握手建立连接的过程。
2. 四次挥手
老样子,先认识到四次挥手的过程是什么样:

- 客户端发送
FIN报文请求断开连接,进入FIN_WAIT_1状态 - 服务端收到请求,返回
ACK应答报文,进入CLOSED_WAIT状态,客户端进入FIN_WAIT_2状态 - 服务端发送
FIN报文请求断开连接,进入LAST_ACK状态,客户端进入TIME_WAIT状态 - 服务端收到
ACK后断开,客户端一段时间后断开
了解到四次挥手的过程后,我们提出以下问题:
- 为什么是四次挥手?为什么不在第一次时就直接断开?
- 为什么客户端在最后需要等待一段时间?
问题一:
引入生活场景。你和你的女朋友(or 男朋友)吵架了,你的女朋友说,我不想聊了,我要断开连接!好的,现在她不说话了,你有两个选择:
- A:不聊就不聊,我也断开连接!
- B:向她解释,千万不能断开连接!
通常情况下,咋们还是选择第二种。你的女朋友确实不会再发送消息给你了,但是不代表她不能听呀!她的话说完了,你的话也许还有呢?
现在回到网络上,客户端断开代表他的数据已经发送完了但是还能接收消息,而服务端可能还存在着需要处理的数据需要发送给客户端。当服务端的数据也已经处理完了,就会发送 FIN 报文同意断开连接。
所以说断开连接需要双方的同意,需要四次挥手!那有没有可能,服务端确实没有什么数据需要处理的情况呢?那肯定有,所以此时我们中间的 ACK 和 FIN 就可以捎带应答的方式发送,四次挥手变成三次回收!
问题二:
保证被动的一方正常的断开:在这里不是主动断开的一方统称为被动的一方。四次挥手的最后客户端向服务端发送一个ACK应答报文表示收到了,服务端这才关闭连接。但是如果该报文没有正常送达呢?那服务器肯定要补发FIN数据包嘛,如果此时客户端早就断线了,在收到服务端重传的FIN报文后,就会回RST报文,这并不是一个好的结束方式。处理历史遗留数据:在这里大家记住一个结论:序列号和初始化序列号并不是无限递增的,无法根据序列号来判断新老数据。会发生回绕为初始值的情况。所以为了避免本次连接在网络中被延迟的数据被下一次新的连接所接收,所以我们需要一个时间来接受这些数据并丢弃!MSL 是报文在网络中的最大生存时间,2MAL 足以处理这些被延迟的报文了。
这就是四次挥手断开连接的过程。
总结
在这一篇文章中,我们介绍了 TCP 的协议段格式,以及保证其可靠传输的确认应答机制,重传机制,着重介绍了三次握手建立连接,四次挥手断开连接的过程,希望大家有所收获!
相关文章:
TCP --- 确认应答机制以及三次握手四次挥手
序言 在前一篇文章中,我们介绍了 UDP协议 (点击查看)👈,该协议给我们的感觉就两个字 — 简单,只是将我们的数据进行简单的添加报头然后发送。当然使用起来虽然简单,但是否能送到目的地,那就要看网络的状态了…...
GPT带我学-设计模式17-装饰器模式
概述 装饰器模式(Decorator Pattern)是一种结构型设计模式,允许你在不改变对象接口的前提下,动态地给对象添加新功能。这个模式通常用于扩展类的功能。 基本结构 组件接口(Component):定义一…...
【Redis】如何在 Ubuntu 上安装 Redis 5
🥰🥰🥰来都来了,不妨点个关注叭! 👉博客主页:欢迎各位大佬!👈 本期内容主要介绍如何在 Ubuntu 上安装 Redis5 一些碎碎念: 本来这期内容介绍如何在 Centos 安装 Redis …...
房屋水电费记账本:内置的数组数据击按钮不能删除,页面手动添加的可以删除
<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>房租水电费记录</title><script type&qu…...
【ubuntu】apt是什么
目录 1.apt简介 2.常用apt指令 2.1安装 2.2更新列表 2.3更新已经安装的软件包 2.4搜索软件包 2.5显示软件包信息 2.6移除软件包 2.7清理无用的安装包 2.8清理无用的依赖项 3.apt和apt-get 3.1区别 3.2 总结 1.apt简介 apt的全称是advanced package …...
堆排序算法的原理与应用
堆排序(Heap Sort)是一种基于堆数据结构的比较排序算法。它具有时间复杂度为 O(n log n) 的优点,并且空间复杂度为 O(1),是一种不稳定的排序算法。本文将详细介绍堆排序的工作原理、步骤以及它的应用场景。 一、堆排序的基本概念…...
【2024版本】Mac/Windows IDEA安装教程
IDEA 2024版本真的很强大,此外JDK发布了最新稳定版 JDK21 ,只有新版本支持JDK 21、JDK22。原来数据库插件不支持redis等一些NoSql的数据库的连接,如果要使用需要自己单独装收费的插件。直接打开idea就很吃内存了,再打开其他一大堆…...
Oracle bbed编译安装及配置
1. 什么是bbed ? Oracle Block Brower and EDitor Tool,是一个可以对oracle data block进行查看,编辑修改的内置工具。对于bbed,oracle本身是不提供支持的。 2. 如何编译bbed环境? 10g版本: 1) 编译bbed cd $ORACL…...
MindSearch 部署到Github Codespace 和 Hugging Face Space
conda init后需要重开终端,不然一键复制会导致后续pip install会安装错环境 还是报错 ImportError: cannot import name AutoRegister from class_registry (/opt/conda/envs/mindsearch/lib/python3.10/site-packages/class_registry/__init__.py)pip install --…...
【Maven】依赖管理,Maven仓库,Maven核心功能
Maven 是一个项目管理工具,基于 POM(Project Object Model,项目对象模型)的概念,Maven 可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件 大白话:Maven 是一个项目管理工…...
Android wifi信号和漫游信号设置
1.wifi信号 /packages/modules/Wifi/framework/java/android/net/wifi/WifiManager.java Deprecated public static int calculateSignalLevel(int rssi, int numLevels) { if (rssi < MIN_RSSI) { //*/update wifi signal return 1;…...
检查cuda和显卡的可用性
检查cuda和显卡的可用性 import torch device_gpu torch.device(cuda if torch.cuda.is_available() else cpu) print(device_gpu) print(torch.cuda.is_available())...
Kotlin:2.0.20 的新特性
一、概述 Kotlin 2.0.20英文版官方文档 Kotlin 2.0.20发布了!这个版本包括对Kotlin 2.0.0的性能改进和bug修复,我们在其中宣布Kotlin K2编译器为Stable。以下是本次发布的一些亮点: 数据类复制函数将具有与构造函数相同的可见性来自默认目标层次结构的源集的静态访…...
Python内存管理与泄漏排查实战
Python内存管理与泄漏排查实战 Python作为一种高级编程语言,因其易读性和丰富的标准库而备受开发者青睐。然而,随着项目的复杂度增加,内存管理问题可能会影响程序的性能,甚至导致内存泄漏。为了构建健壮且高效的应用程序…...
828华为云征文|华为云Flexus云服务器X实例搭建部署H5美妆护肤分销商城、前端uniapp
准备国庆之际,客户要搭个 H5 商城系统,这系统好不容易开发好啦,就差选个合适的服务器上线。那可真是挑花了眼,不知道哪款性价比高呀!就像在琳琅满目的选择前。最终慧眼识珠,选择了华为云 Flexus X。至于为什…...
初学51单片机之I2C总线与E2PROM二
总结下上篇博文的结论: 1:ACK信号在SCL为高电平期间会一直保持。 2:在字节数据传输过程中如果发送电平跳变,那么电平信号就会变成重复起始或者结束的信号。(上篇博文的测试方法还是不能够明确证明这个结论࿰…...
Kafka学习笔记(一)Kafka基准测试、幂等性和事务、Java编程操作Kafka
文章目录 前言4 Kafka基准测试4.1 基于1个分区1个副本的基准测试4.2 基于3个分区1个副本的基准测试4.3 基于1个分区3个副本的基准测试 5 Java编程操作Kafka5.1 引入依赖5.2 向Kafka发送消息5.3 从Kafka消费消息5.4 异步使用带有回调函数的生产消息 6 幂等性6.1 幂等性介绍6.2 K…...
结合vueuse实现图片懒加载
介绍 为什么要有懒加载? 在一个网页中如果有很多张图片,那么用户初进这个页面的时候不必一次性把所有图片都加载出来,否则容易造成卡顿和浪费。应该是,用户的视图页面滑到该图片的位置,然后再把该图片加载出来。 前置…...
Mysql数据库--聚合查询、分组查询、联合查询(不同的连接方式)
文章目录 1.查询的进阶版1.1查询搭配插入进行使用1.2聚合查询1.3group by分组查询1.4联合查询之笛卡尔积1.5左外连接,右外连接介绍join on1.6自连表 1.查询的进阶版 1.1查询搭配插入进行使用 我们首先创建两张表,一个叫做student,一个叫做student2,两个…...
计算机视觉——图像修复综述篇
目录 1. Deterministic Image Inpainting 判别器图像修复 1.1. sigle-shot framework (1) Generators (2) training objects / Loss Functions 1.2. two-stage framework 2. Stochastic Image Inpainting 随机图像修复 2.1. VAE-based methods 2.2. GAN-based methods …...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
