news 2026/10/3 7:36:28

【从0开始学习计算机网络】| TCP 是怎么保证数据不丢、网络不堵的?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【从0开始学习计算机网络】| TCP 是怎么保证数据不丢、网络不堵的?

🌈个人主页:一条泥憨鱼(欢迎各位大佬莅临)

❄️《数据结构》 ❄️《AI与Agent那些事》

❄️《从0开始学计算机网络》 ❄️《后端开发》

前言:

你肯定遇到过这种情况:打开一个网页,进度条冲到 80% 突然不动了,你盯着屏幕等了三四秒,心里开始嘀咕"是不是网断了",然后它又突然一下加载完了。

这个"卡一下又冲上去"的现象,不是你的网坏了,也不是浏览器抽风。它背后是TCP 的两套机制在互相拉扯:一套负责"数据别丢",一套负责"网络别堵"。这两套机制配合起来,我们下载文件才不会下错,看网页才不会乱序。

但这里有个问题:网络本身是会丢包的,路由器也会堵车,凭什么 TCP 就能保证数据不丢、不乱?

接下来就把 TCP 的可靠性机制和拥塞控制四个阶段(慢启动、拥塞避免、快重传、快恢复)讲清楚。

先搞懂 TCP 到底在解决什么问题

要理解 TCP,得先知道它下面的那个协议——IP——有多不靠谱。

你可以把 IP 想象成一个"只管扔包裹,不管结果"的快递员。你把包裹交给它,它负责往目的地扔,但

- 包裹可能丢(网络丢包)

- 包裹可能后发先到(乱序)

- 包裹可能重复送(重复包)

- 它也不知道对方到底收没收到

IP 协议就这德行,它只负责"尽力而为",不保证任何东西。

那问题来了:我们下载一个 100MB 的文件,分成几万个数据包发出去,中间丢了几个,为什么文件还能完好无损?

因为 TCP 在 IP 之上又加了一层"靠谱快递公司"。IP 负责扔包裹,TCP 负责:给包裹编号、要求对方签收、丢了就重发、乱了就重排。

具体来说,TCP 保证可靠传输靠四个手段:

第一,序号。

每个字节的数据都有一个编号。比如你要发 1000 字节,第一个字节编号是 1,第二个是 2……这样接收方就知道哪个包该排在哪个位置。

第二,确认应答(ACK)。

接收方每收到一段数据,就回一个 ACK,意思是"我收到编号 X 之前的所有数据了"。发送方收到 ACK,就知道这段数据安全到达了。

第三,超时重传。

如果发送方发出去一个包,等了很久没收到对应的 ACK,就认为它丢了,重新发一遍。

第四,滑动窗口。

这个稍微复杂点,简单说就是"不用发一个等一个",可以一次发一批,提高效率。这里先点到为止,你只要知道它是用来提升传输速度的就行。

举个具体例子。发送方发了三个包:序号 1、序号 2、序号 3。接收方收到 1 和 3,但 2 丢了。它会回两个 ACK:"我要序号 2"(收到 1 之后期待的)、"我要序号 2"(收到 3 之后发现缺了 2,还是期待 2)。发送方一看,对方一直在喊"我要 2",就知道 2 丢了,重发一遍。

这套机制保证了数据不丢、不乱。但这里有个新问题:如果发送方不管不顾,一次把几万个包全扔出去,网络受得了吗?

受不了。这就是拥塞控制要解决的问题。

慢启动——为什么一开始要"慢慢来"

这里有个反直觉的点:TCP 发数据,不是一上来就猛发,而是从一个很小的量开始,慢慢加。

为什么要这样?想象你往一个杯子里倒水。你不知道杯子多大,也不知道水会不会溢出来。聪明的做法是先倒一点点,看看水面到哪了,再决定下一步倒多少。如果你一上来就整壶倒下去,大概率洒一桌。

TCP 也是这个思路。它维护一个叫拥塞窗口(cwnd)的东西,你可以理解成"我一次最多能发多少数据,而不会把网络搞堵"。

这里要注意区分两个"窗口":

- 拥塞窗口(cwnd):管的是"网络堵不堵",是发送方自己估算的

- 接收窗口(rwnd):管的是"对方收不收得下",是接收方告诉发送方的

发送方实际能发多少,取这两个的最小值。也就是说,既不能超过网络的承载能力,也不能超过对方的接收能力。

好,回到慢启动。它一开始把 cwnd 设成很小,比如 1 个 MSS(MSS 是"一个数据包最大能装多少数据",通常是 1460 字节左右)。然后:

- 发出去 1 个包,收到 ACK,cwnd 变成 2

- 发出去 2 个包,收到 2 个 ACK,cwnd 变成 4

- 发出去 4 个包,收到 4 个 ACK,cwnd 变成 8

- ……

看出来了吗?1、2、4、8、16……每过一个往返时间(RTT),窗口就翻一倍。这是指数增长。

为什么叫"慢启动"?因为它起点很低,从 1 开始。但它的增长速度其实一点都不慢,是指数级的。

那什么时候停?TCP 设了一个阈值,叫慢启动阈值(ssthresh)。当 cwnd 涨到 ssthresh,说明"网络可能快到临界点了",就不能再翻倍了,得换个策略。

这个新策略,就是拥塞避免。

拥塞避免——快到临界点了,改成稳步走

慢启动的指数增长很爽,但也很危险。你想,cwnd 从 1 涨到 1024 只需要 10 个 RTT,如果继续翻倍,很快就会把网络压垮。

所以到了 ssthresh 之后,TCP 切换成拥塞避免策略:不再翻倍,改成每过一个 RTT,cwnd 只加 1。

这就是从"指数增长"变成了"线性增长"。

打个比方:你在高速上开车,前面路很空,你可以猛踩油门加速(慢启动)。但快到收费站了,你得从加速改成匀速,稳稳地往前挪(拥塞避免)。如果你还猛踩油门,前面一堵,你就得急刹,甚至追尾。

那什么时候会"撞车"呢?答案是丢包。

在 TCP 看来,丢包就是网络在喊:"我堵了!"因为正常情况下,数据包不应该丢。一旦丢了,说明中间某个路由器的缓冲区满了,开始丢包了。

丢包有两种情况,对应两种不同的处理方式:

-超时重传:等了很久(超过 RTO 时间)都没收到 ACK,说明可能丢得很严重,网络堵得厉害

-快重传:连续收到 3 个重复 ACK,说明只是丢了一个包,网络还没完全瘫

这两种情况处理方式不一样,尤其是第二种,诞生了"快重传"和"快恢复"。

快重传与快恢复——丢了一个包,别从头再来

这是全文最容易被讲糊涂的地方,我们分两步说。

快重传:不用等超时,立刻重发

前面说过,接收方收到乱序的包时,会重复发同一个 ACK。比如发送方发了 1、2、3、4、5,结果 3 丢了。接收方收到 1、2,回 ACK"我要 3";收到 4,发现缺 3,还是回 ACK"我要 3";收到 5,还是回 ACK"我要 3"。

发送方一看,收到了 3 个"我要 3"的重复 ACK,立刻意识到:"3 丢了!"于是不等超时,马上重传 3。

这就是快重传。它的好处是快,不用傻等 RTO 超时,省了好几秒。

用生活类比:你去取快递,对方一直跟你说"我要第 5 个",说了一遍又一遍,你就知道第 5 个没送到,赶紧补发,不用等到对方投诉。

快恢复:砍一半,别回到起点

重传之后,接下来怎么办?

按照老思路,既然丢包了,说明网络堵了,那就把 cwnd 打回 1,重新慢启动。但这样太狠了,明明只是丢了一个包,网络还在正常工作,你直接回到起点,效率损失太大。

所以 TCP 引入了快恢复:既然只是丢了一个包,说明网络没完全瘫,那就把 cwnd 砍一半(而不是打回 1),然后直接进入拥塞避免,线性增长。

对比一下:

- 超时重传(严重情况):cwnd 打回 1,重新慢启动

- 快重传 + 快恢复(轻微情况):cwnd 砍半,直接拥塞避免

这样一来,cwnd 的曲线就变成了经典的"锯齿"形状:慢启动指数上升 → 拥塞避免线性上升 → 丢包 → 砍半 → 再线性上升 → 再丢包 → 再砍半……

每次砍半之后,网络又能撑一段时间,然后再次丢包,再次砍半。这就是 TCP 拥塞控制的稳态。

把四个阶段串起来

到这里,四个阶段就讲完了。我们用一条时间线回顾一下:

1. 慢启动:cwnd 从 1 开始,指数增长(1→2→4→8……),快速探测网络容量

2. 拥塞避免:cwnd 到达 ssthresh 后,改成线性增长(每个 RTT 加 1),稳扎稳打

3. 快重传:收到 3 个重复 ACK,立刻重传丢失的包,不等超时

4. 快恢复:cwnd 砍半,直接进入拥塞避免,不回到起点

这些机制,你写代码的时候基本不用管,操作系统内核已经替你做好了。但理解它们,能帮你解释很多"玄学"现象:

- 为什么小文件传输感觉特别慢?因为慢启动阶段 cwnd 还很小,没涨起来就传完了

- 为什么弱网环境下要调 TCP 参数?因为默认的初始 cwnd 和 ssthresh 可能不适合高延迟网络

- 为什么 QUIC/HTTP3 要绕开 TCP 重做一套拥塞控制?因为 TCP 在内核里,改起来慢,而且队头阻塞问题不好解决

如果你想把今天讲的东西亲眼看看,可以试试这两个工具:

- `ss -i`:在 Linux 上敲这个命令,能看到当前连接的 cwnd、ssthresh、RTT 等参数

-Wireshark:抓包神器,能看到每一个数据包、每一个 ACK,甚至能画出 cwnd 随时间变化的曲线

打开 Wireshark 抓一次自己访问网页的流量,你会对今天讲的这些有完全不一样的理解。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 7:36:08

Vibe-Research 多空辩论教程:让 AI 帮你戳破投资观点的漏洞

Vibe-Research 多空辩论教程:让 AI 帮你戳破投资观点的漏洞 【免费下载链接】Vibe-Research Vibe-Research: Your Personal Trading Research Agent A股/美股/港股 的个人投研 Agent:每日复盘、资讯雷达、个股数据、板块中心、我的持仓、研究记录、回测…

作者头像 李华
网站建设 2026/10/3 7:36:00

判断推理总在及格线徘徊?图推和逻辑别混着练

我第一次系统做判断推理,是把图形推理和逻辑判断放在一起刷的,结果两边都没长进。后来才想明白,这两个模块考的是完全不同的能力,混在一起练,等于哪一科都没练透。 一、图形推理靠的是套路积累,不是灵光一闪…

作者头像 李华
网站建设 2026/10/3 7:35:40

语音合成TTS项目:自然度、情感和实时部署怎么兼得

摘要:一篇能直接复用的项目实战 这是一篇可以直接照着做的语音与音频长文项目实战。项目面向“有声内容、客服播报、导航提示和无障碍阅读”,核心方法是“声学模型、声码器、音素对齐、时长预测、情感控制”,技术栈以Python、VITS、Coqui TTS、PyTorch、ONNX、FastAPI为主。…

作者头像 李华
网站建设 2026/10/3 7:35:21

《FastAPI + SQLAlchemy异步实战(二):构建用户接口》

《FastAPI SQLAlchemy异步实战(二):构建用户接口》此部分讲解对用户功能接口的讲解,相信对于大部分后端项目来说,用户功能相关接口一定都是必不可少的,相较于新闻接口这部分难度更大,涉及用户注…

作者头像 李华
网站建设 2026/10/3 7:34:51

大模型知识库项目:数据治理、向量库和权限系统怎么做

摘要:一篇能直接复用的项目实战 这是一篇可以直接照着做的大模型与智能体长文项目实战。项目面向“跨部门知识共享、研发文档检索和合规制度查询”,核心方法是“元数据过滤、增量索引、权限感知检索、去重聚类、引用链路”,技术栈以Python、PostgreSQL、Milvus、Redis、Min…

作者头像 李华