TCP的可靠性问题

  • 流量控制端到端的速率匹配 ,解决「发送方发送速度 > 接收方处理速度」的问题,核心是滑动窗口 + 通告窗口 (rwnd),防止接收方缓冲区溢出;
  • 拥塞控制网络层面的拥堵避免 ,解决「发送方发送速度 > 网络承载能力」的问题,核心是拥塞窗口 (cwnd) + 慢启动 / 拥塞避免 / 快重传 / 快恢复,防止网络崩溃;
  • 发送方实际发送窗口实际窗口 = min(拥塞窗口cwnd, 通告窗口rwnd) ------ 面试高频考点,二者共同限制发送方的发送速率;
  • TCP 可靠传输的核心保证序列号 + 确认号 + 滑动窗口 + 超时重传 + 快重传 + 数据校验 + 乱序重排 + 重复丢弃,是多机制协同的结果。

一、TCP 流量控制

1. 流量控制的核心定义与解决的问题

流量控制 是 TCP 基于「接收方处理能力」的速率调节机制,目标是:

发送方的发送速率,匹配接收方的接收速率,防止接收方缓冲区被填满,导致数据丢失。

为什么需要流量控制?

TCP 是面向字节流的协议,接收方会为每个 TCP 连接分配一个接收缓冲区

  • 发送方不断发送数据 → 数据进入接收方内核缓冲区 → 应用层调用 read() 从缓冲区读取数据;
  • 如果发送方发送速度过快,应用层读取速度跟不上,接收缓冲区会被填满,后续到达的数据会被内核丢弃,造成数据丢失,触发重传,降低传输效率。

流量控制的本质:接收方通过「通告窗口」告诉发送方自己的剩余缓冲区大小,发送方据此调整发送速率

2. 流量控制的核心实现:滑动窗口(Sliding Window)+ 通告窗口(rwnd)

TCP 的滑动窗口是流量控制的核心载体,也是可靠传输的基础,分为「发送窗口」和「接收窗口」,二者协同工作。

概念定义

|----------------|-----------------------------------------------------|---------|
| 概念 | 核心含义 | 归属方 |
| 接收窗口(rwnd) | 接收方当前「剩余可用的缓冲区大小」,由接收方通过 TCP 头部的「窗口字段」告诉发送方 | 接收方 |
| 发送窗口 | 发送方在未收到确认的情况下,最多可以发送的字节数 | 发送方 |
| TCP 头部窗口字段 | 占 16 位,用于接收方通告自己的 rwnd,最大值为 65535 字节(可通过窗口扩大因子扩展) | 双向 |

滑动窗口的工作流程(以「发送方视角」为例)
  • 初始阶段 :接收方告诉发送方 rwnd = 1000 字节(表示接收缓冲区剩余 1000 字节),发送方的发送窗口 = rwnd = 1000
  • 发送数据:发送方在发送窗口内连续发送 500 字节数据,此时发送窗口内「已发送未确认」的字节数为 500,剩余可发送字节数为 500;
  • 接收方确认 :接收方收到 500 字节数据,应用层读取了 300 字节,剩余缓冲区大小变为 1000 - 500 + 300 = 800,于是发送 ACK 确认报文,携带 rwnd = 800 + 确认号 ack = 501
  • 窗口滑动 :发送方收到 ACK 后,发送窗口向右滑动 ------ 已确认的 500 字节移出窗口,窗口的起始位置变为 501,新的发送窗口大小 = rwnd = 800
  • 循环往复:发送方在新的发送窗口内继续发送数据,直到接收方缓冲区满。

流量控制的关键补充:零窗口探测(避免死锁)

当接收方缓冲区满时,会通告 rwnd = 0,发送方会停止发送数据。但此时可能出现「接收方缓冲区有空闲后,发送的 rwnd > 0 报文丢失」的情况,导致发送方永远等待,形成死锁。

TCP 解决这个问题的机制是 持续计时器(Persistent Timer)

  • 发送方收到 rwnd = 0 后,启动持续计时器;
  • 计时器超时后,发送方发送一个 零窗口探测报文(仅 1 字节数据);
  • 接收方收到后,必须回应当前的 rwnd,发送方据此恢复发送或继续等待。
3. 流量控制的特点
  1. 端到端:仅涉及发送方和接收方,不关心网络中间链路的状态;
  2. 基于接收缓冲区:窗口大小由接收方的缓冲区剩余空间决定;
  3. 滑动窗口是「字节流窗口」:TCP 是面向字节的,窗口大小以字节为单位,而非数据包个数。
4. 必须分清【发送窗口】和【发送缓冲区】
1. TCP「发送窗口」:是「软件层面的发送许可」,没有「内存占用 / 释放 / 扩容」的说法

TCP 的发送窗口(swnd = min(rwnd, cwnd)),本质是一个「数字」、一个「发送权限」

  • 它的作用:告诉你「最多能发送多少字节的未确认数据」;
  • 它的变化:收到 ACK 后,窗口左边界右移(释放许可),窗口可能变大 / 变小 / 不变,但它只是一个逻辑上的范围限制 ,不是一块内存,不存在「释放内存」「扩容」的操作
  • 你之前说的「释放了已经发送且确认的」,不是窗口释放,是「发送缓冲区」释放了这部分内存
2. TCP「发送缓冲区」:是「内核给 TCP 连接分配的物理内存块」,有「占用 / 释放 / 空闲」的说法

这才是你真正关心的「内存载体」,不管是内核自带的,还是你自己写的应用层缓冲区,本质都是一块连续的物理内存

  • 所有你调用send()发送的数据,都会先拷贝到这块内存里,内核再从缓冲区里取数据,通过网卡发出去;
  • 内核确认「某段数据已被接收方 ACK」后,会把缓冲区里这段数据的内存标记为空闲可用 → 这就是你说的「释放」;
  • 这个「释放」,不是把内存归还给操作系统、删掉这块内存 ,而是:缓冲区的总大小不变,只是里面多了一块「空闲的内存空间」

二、TCP 拥塞控制

1. 拥塞控制的核心定义与解决的问题

拥塞控制 是 TCP 基于「网络承载能力」的速率调节机制,目标是:

发送方的发送速率,匹配网络的传输能力,防止过多数据注入网络导致「网络拥塞→数据包丢失→重传加剧→网络崩溃」的恶性循环。

为什么需要拥塞控制?

流量控制只考虑了端到端的速率匹配,但忽略了网络的状态

  • 即使接收方缓冲区充足(rwnd 很大),如果网络带宽小、路由器队列满,发送方发送的大量数据包会在网络中丢失;
  • 丢失的数据包会触发发送方超时重传,重传的数据包进一步加剧网络拥堵,形成「拥塞崩溃」。

拥塞控制的本质:发送方通过「拥塞窗口」估算当前网络的拥塞程度,据此调整发送速率

2. 拥塞控制的核心概念

窗口定义

|-----------------|--------------------------------------|----------------------------|
| 概念 | 核心含义 | 决定因素 |
| 拥塞窗口(cwnd) | 发送方根据网络拥塞程度估算的「最大可发送字节数」,反映当前网络的承载能力 | 网络拥塞程度(丢包则减小,无丢包则增大) |
| 慢启动阈值(ssthresh) | 区分「慢启动阶段」和「拥塞避免阶段」的临界值,单位为字节 | 初始值通常为 65535 字节,拥塞发生时动态调整 |
| 实际发送窗口 | 实际窗口 = min(cwnd, rwnd) | 拥塞窗口(网络限制)和通告窗口(接收方限制)的最小值 |

发送方的发送速率由「网络」和「接收方」共同限制,二者取其小,这是 TCP 速率调节的核心逻辑。

TCP 拥塞控制通过 慢启动、拥塞避免、快重传、快恢复 四个阶段,动态调整 cwndssthresh,这是 Linux 内核 TCP 协议栈的标准实现(如 Reno 算法)。

阶段 1:慢启动(Slow Start)------ cwnd 指数增长

核心目标:在网络空闲时,快速探测网络的可用带宽,避免一开始就发送大量数据导致拥塞。

  • 初始状态 :连接建立后,cwnd = 初始值(通常为 1~2 个 MSS,MSS 是最大报文段长度,默认 1460 字节),ssthresh = 初始阈值(如 65535 字节);
  • 增长规则 :发送方每收到一个 ACK 确认,cwnd *= 2(指数增长);
    • 例:cwnd=1MSS → 发送 1 个 MSS 数据 → 收到 ACK → cwnd=2MSS → 发送 2 个 MSS → 收到 ACK → cwnd=4MSS...
  • 阶段切换条件 :当 cwnd ≥ ssthresh 时,进入拥塞避免阶段
阶段 2:拥塞避免(Congestion Avoidance)------ cwnd 线性增长

核心目标:在不引发拥塞的前提下,缓慢增加发送速率,充分利用网络带宽。

  1. 增长规则 :发送方每收到一个 ACK 确认,cwnd += 1(线性增长,而非指数);
    • 例:cwnd=ssthresh → 每轮发送后 cwnd +=1,速率平稳提升;
  2. 拥塞判断:当出现「超时重传」或「3 次重复确认」时,判定网络发生拥塞,进入拥塞处理流程。
阶段 3:快重传(Fast Retransmit)------ 快速检测丢包,避免超时

核心目标:在超时前快速检测到丢包并重传,避免进入慢启动阶段,提升效率。

  1. 触发条件 :发送方收到 3 个重复的 ACK 确认 (表示接收方收到了乱序的数据包,中间有一个数据包丢失);
    • 例:发送方发送 pkt1, pkt2, pkt3 → 接收方收到 pkt1, pkt3 → 连续发送 3 次 ack=pkt2的序号
  2. 处理逻辑
    • 发送方立即重传丢失的数据包(pkt2),无需等待超时计时器触发
    • 不启动慢启动,而是进入快恢复阶段

这里我们还要解释一下三个ACK是怎么来的

铁律 1:TCP 的 ACK 是「累计确认 + 期望序号」,只认「我要的下一个包」,不认「我收到的乱序包」

接收方返回的 ACK 号 = 「我期望收到的、缺失的、最小的那个字节序号」

只要这个「缺失的包」没收到,无论后续收到多少个后续的包,ACK 号永远不变

举个例子:你要收 pkt1 (seq=1)、pkt2 (seq=2)、pkt3 (seq=3),你的expected_seq=1

  1. 收到 pkt1 → 期望的下一个是 pkt2,返回 ACK=2expected_seq 更新为 2;

  2. 没收到 pkt2,但是收到了 pkt3 → 此时「缺失的最小包是 pkt2」,依然返回 ACK=2expected_seq 依然是 2,绝不更新;

  3. 就算再收到 pkt4/pkt5 → 只要 pkt2 没到,永远返回 ACK=2,ACK 号纹丝不动。

铁律 2:接收方收到「乱序包」时,会立即、主动、无条件发送 1 个重复的 ACK

TCP 协议规定:接收方一旦发现收到的数据包是「乱序」的(包的序号 > 自己的expected_seq),不需要等、不需要攒,必须立刻发一个「重复的 ACK」给发送方

  • 这个「重复 ACK」的作用:给发送方发「告警信号」 → 我收到了后续的包,但是你发的某个包丢了,我这里卡住了!
  • 这个行为是「立即发送」,没有延迟,没有合并,来一个乱序包,就发一个重复 ACK。

按 2 条铁律,一步步数 ACK,精准数出 3 个重复 ACK,全程无跳跃:

步骤 1:收 pkt1 → 返回 【ACK=2】(第 1 个,正常 ACK)

步骤 2:收 pkt3 → 乱序 → 返回 【ACK=2】(第 2 个,第 1 次重复 ACK)

步骤 3:收 pkt4 → 乱序 → 返回 【ACK=2】(第 3 个,第 2 次重复 ACK)

此时发送方收到的 ACK 序列:ACK=2ACK=2ACK=2 → 正好 3 个重复的 ACK!

发送方内核检测到「连续 3 个相同的 ACK 号」,立刻判定:我发的 pkt2 丢了! → 触发「快重传」,不等超时定时器到期,立即重传 pkt2

阶段 4:快恢复(Fast Recovery)------ 快速恢复拥塞窗口,避免退避

核心目标 :拥塞发生后,快速恢复 cwnd,避免慢启动导致的速率骤降。

  1. 处理逻辑
    • 第一步:调整慢启动阈值 ssthresh = cwnd / 2(将阈值设为当前拥塞窗口的一半);
    • 第二步:设置 cwnd = ssthresh + 3(补偿 3 个重复 ACK 对应的已发送数据);
    • 第三步:进入拥塞避免阶段cwnd 线性增长;

对比超时重传的处理

  • 如果是超时重传 (严重拥塞),则 ssthresh = cwnd / 2cwnd = 初始值,重新进入慢启动阶段。
3. 为什么 TCP 要把「3 次重复 ACK」定为快重传的触发阈值?

① 用「3 次」而不是「1/2 次」:避免「误判」,排除「网络乱序」的干扰

真实的网络中,不一定是丢包导致乱序,也可能是「网络延迟」导致的包到达顺序颠倒(比如 pkt2 绕远路,pkt3 先到,但是 pkt2 随后就到)。

  • 如果触发阈值是 1 次:只要有一个乱序包就重传,会导致大量「没必要的重传」,浪费带宽;
  • 如果触发阈值是 2 次:依然有概率是网络轻微延迟,误判率还是有点高;
  • 如果触发阈值是3 次:几乎可以 100% 确定「不是网络乱序,而是真的丢包了」------ 一个包延迟可以理解,连续 3 个后续包都到了,丢失的那个包还没到,基本就是丢了。

② 用「3 次」而不是「更多次」:兼顾「速度」,比超时重传快 10 倍以上

TCP 的「超时重传」定时器,默认超时时间是 200~500ms (Linux 内核),如果等超时再重传,丢包后要等几百 ms 才能恢复,传输效率极低;而「3 次重复 ACK」的触发时间,只有 几十 ms ------ 发送方收到 3 个重复 ACK 就立即重传,几乎是「丢包即发现,发现即重传」,这也是「快重传」的名字由来。

一句话总结:3 次重复 ACK,是 TCP 协议在「不误判」和「不慢」之间,找到的最优解

4. 拥塞控制的补充:Linux 内核的拥塞算法

现代 Linux 内核支持多种拥塞控制算法,可通过 sysctl 配置,高性能服务器可根据场景选择:

  • Reno:基础算法,即上述的「慢启动 + 拥塞避免 + 快重传 + 快恢复」;
  • CUBIC :Linux 默认算法,针对长肥管道(高带宽高延迟网络)优化,cwnd 增长更平滑;
  • BBR:Google 提出的算法,基于带宽和延迟的探测,适合高并发、低延迟场景(如游戏服务器、直播服务器)。

三、TCP 可靠传输的核心保证机制

TCP 是可靠的字节流传输协议 ,其「可靠性」体现在:保证数据的有序、无丢失、无重复、无损坏地到达接收方

这种可靠性不是单一机制实现的,而是多个核心机制协同作用的结果。

1. 核心机制 1:序列号与确认号(可靠传输的基石)

这是 TCP 可靠传输的最核心机制,解决了「数据乱序、重复、丢失」的问题。

  • 序列号(Sequence Number)
    • TCP 为每个字节的数据分配一个唯一的序列号(seq);
    • 发送方发送数据包时,携带该包第一个字节的序列号;
    • 作用:标识数据的顺序,接收方据此判断是否乱序、是否重复。
  • 确认号(Acknowledgment Number)
    • 接收方收到数据后,发送 ACK 报文,携带的确认号 = 「期望收到的下一个字节的序列号」 = 「已收到的最后一个字节的序列号 + 1」;
    • 作用:告诉发送方「我已经收到了哪些数据,你可以继续发送后续数据」;
    • 累计确认:TCP 采用累计确认,只要确认号为 N,就表示「所有小于 N 的字节都已收到」。
2. 核心机制 2:滑动窗口(流量控制 + 可靠传输的载体)

滑动窗口不仅是流量控制的工具,也是实现高效可靠传输的核心:

  • 发送窗口:限定了发送方「已发送未确认」的最大字节数,避免发送过多数据导致拥塞;
  • 接收窗口:接收方通过窗口通告自己的处理能力,同时对乱序数据进行缓存;
  • 窗口滑动:只有收到确认号,发送窗口才会滑动,确保数据的有序传输。
3. 核心机制 3:重传机制(解决数据丢失)

当数据丢失时,TCP 通过超时重传快重传两种方式重传丢失的数据,保证无丢失。

  • 超时重传
    • 发送方为每个已发送的数据包启动超时计时器
    • 如果计时器超时仍未收到 ACK,判定数据丢失,重传该数据包;
    • 超时时间(RTO)不是固定的,而是基于往返时间(RTT) 动态计算,确保适应不同网络延迟。
  • 快重传
    • 如前文所述,收到 3 次重复 ACK 后,立即重传丢失的数据包,无需等待超时,提升效率。
4. 核心机制 4:数据校验与损坏丢弃(解决数据损坏)

TCP 头部包含 16 位校验和字段,用于检测数据在传输过程中是否损坏:

  • 发送方:计算数据包的校验和(包括 TCP 头部 + 数据 + 伪头部),填入头部;
  • 接收方:收到数据包后,重新计算校验和;
  • 如果校验和不匹配,判定数据损坏,直接丢弃该数据包,不发送 ACK,触发发送方超时重传。
5. 核心机制 5:乱序重排与重复数据丢弃(解决乱序和重复)
  • 乱序重排 :接收方会为乱序到达的数据包分配乱序缓冲区,缓存未按顺序到达的数据;当缺失的数据包到达后,接收方将乱序缓冲区中的数据按序列号排序,拼接成完整的字节流,再交给应用层。
  • 重复数据丢弃:接收方根据序列号判断数据是否重复,如果是重复数据,直接丢弃,不交给应用层,也不重复发送 ACK。
6. 核心机制 6:连接管理(三次握手 + 四次挥手)(保证连接的可靠建立与关闭)
  • 三次握手:建立连接时,同步双方的序列号和确认号,验证双方的收发能力,确保连接可靠建立;
  • 四次挥手:关闭连接时,保证双方的数据都传输完毕,避免数据丢失,同时通过 TIME_WAIT 状态防止失效报文干扰。
7. 核心机制 7:拥塞控制(保证网络层面的可靠传输)

拥塞控制通过调整发送速率,避免网络拥塞导致的数据丢失,从宏观上保证了传输的可靠性 ------ 如果网络崩溃,再强的端到端机制也无法保证可靠传输。

相关推荐
陌路202 小时前
RPC分布式通信(1)--分布式通信讲解
分布式·网络协议·rpc
edisao2 小时前
二。星链真正危险的地方,不在天上,而在网络底层
大数据·网络·人工智能·python·科技·机器学习
tobias.b2 小时前
408真题解析-2009-34-网络-数据传输速率
网络·408考研·408真题解析
佑白雪乐2 小时前
<Linux基础第3集>清华镜像源配置+网络基础概念理解(IP地址+网卡+网关+子网掩码+DNS...)
linux·网络·tcp/ip
MengFly_2 小时前
Java广播 —如何利用广播做服务发现
java·网络·服务发现
Macbethad2 小时前
半导体EFEM设备TwinCAT程序设计方案
java·前端·网络
再出发new start2 小时前
IPV6基础 二
网络
小小代码狗3 小时前
PHP伪协议和文件包含
网络·网络安全·php
聚铭网络3 小时前
聚铭网络再次入选数世咨询《中国数字安全价值图谱》“日志审计”推荐厂商
网络·安全