TCP 7 (滑动窗口,流量控制)

TCP滑动窗口(TCP Sliding Window)是TCP协议中用于实现流量控制拥塞控制的核心机制。它通过一种巧妙的方式,在保证数据可靠传输的同时,极大地提升了网络带宽的利用率。

简单来说,滑动窗口就像是接收方告诉发送方:"我现在还能接收多少数据",发送方则根据这个信息来动态调整自己的发送速率。

为什么需要滑动窗口?

在没有滑动窗口的早期,TCP使用一种名为"停等协议"(Stop-and-Wait)的机制。它的工作流程是:

  1. 发送方发送一个数据包。
  2. 等待接收方返回确认(ACK)。
  3. 收到ACK后,再发送下一个数据包。

这种方式非常低效,尤其是在高延迟的网络中(例如卫星链路),发送方大部分时间都在等待ACK,导致网络带宽被严重浪费。

滑动窗口的优势在于它实现了流水线传输:允许发送方在收到ACK之前,连续发送多个数据包,从而让网络链路保持繁忙,大幅提升了传输效率。

滑动窗口的核心原理

滑动窗口的本质是一个动态变化的字节范围,它以字节为单位进行管理。发送方和接收方都维护着自己的窗口。

关键概念与变量

为了理解其工作原理,我们需要了解几个关键变量:

  • 接收窗口 (rwnd, Receive Window):由接收方决定并通告给发送方,表示接收方缓冲区当前还能容纳多少字节的数据。
  • 拥塞窗口 (cwnd, Congestion Window):由发送方根据网络拥塞状况自行估算,用于防止网络过载。
  • 实际发送窗口 :发送方最终能发送的数据量,由接收方处理能力和网络状况共同决定。其计算公式为:
    实际发送窗口 = min(接收窗口rwnd, 拥塞窗口cwnd)

在发送方,窗口内部通常被划分为四个区域:

区域 描述
已发送且已确认 数据已被接收方确认,可以从发送缓冲区中移除。
已发送但未确认 数据已发出,正在等待接收方的ACK,必须保留以备重传。
可发送但未发送 在窗口范围内,可以立即发送的数据。
不可发送 超出当前窗口范围,必须等待窗口滑动后才能发送的数据。

滑动窗口的工作流程

滑动窗口的工作过程可以看作是一个"滑动"的动作:

  1. 发送数据:发送方将"可发送但未发送"区域的数据连续发送出去,这些数据进入"已发送但未确认"状态。
  2. 接收与确认:接收方收到数据后,会返回一个确认号(ACK),该ACK号表示"该序号之前的所有数据都已正确接收"。同时,ACK报文中会携带接收方当前的rwnd大小。
  3. 窗口滑动:发送方收到ACK后,窗口的左边界(SND.UNA,即最早未确认的字节序号)会向右移动,覆盖掉"已发送且已确认"的区域。
  4. 继续发送:随着窗口向右"滑动",之前"不可发送"的数据可能进入"可发送但未发送"区域,发送方可以继续发送新数据。

这个过程就像一个在数据流上移动的"窗口",不断地发送、确认、滑动,实现了高效的数据流传输。

滑动窗口的三大作用

  1. 流量控制 (Flow Control)
    这是滑动窗口最核心的作用。它防止发送方发送数据过快,超过接收方的处理能力,从而避免接收方缓冲区溢出。当接收方应用读取数据变慢时,其缓冲区空间减少,rwnd会相应减小,发送方收到这个信息后就会降低发送速率。

  2. 提高传输效率
    通过允许连续发送多个数据包,而不是"发一个等一个",滑动窗口充分利用了网络带宽,将信道利用率从极低水平提升到90%以上。

  3. 保证可靠传输
    滑动窗口机制与确认、重传机制紧密结合。对于窗口内已发送但未确认的数据,如果长时间未收到ACK(超时)或收到多个重复的ACK(快速重传),发送方会认为数据丢失并进行重传,从而保证了数据传输的可靠性。

流量控制(Flow Control)

是用于解决发送方与接收方速度不匹配 问题的核心机制。它的核心目标是保护接收方,防止发送方发送数据的速度过快,超过了接收方的处理能力,导致接收方缓冲区溢出和数据丢失。

你可以把它想象成一个水龙头(发送方)和一个水杯(接收方)。流量控制就是确保水龙头出水的速度,不会快到让水从杯子里溢出来。

核心目标:端到端的速度匹配

流量控制是一种**端到端(End-to-End)**的机制,它只关心通信两端的处理能力,而不关心中间网络的拥塞状况。

  • 问题场景:如果发送方是一台高性能服务器,而接收方是一台处理能力有限的手机,服务器持续高速发送数据会迅速填满手机的接收缓冲区。
  • 解决方案:通过流量控制,接收方可以动态地告知发送方:"我还能接收多少数据",发送方则据此调整发送速率,实现速度上的匹配。

核心机制:接收窗口 (rwnd)

流量控制的实现依赖于 TCP 报文首部中的一个 16 位字段------窗口大小(Window Size) 。这个字段的值就是接收窗口(rwnd, Receiver Window)

其工作流程如下:

  1. 通告窗口 :接收方在每次向发送方回复确认(ACK)时,都会在 ACK 报文中携带自己当前的 rwnd 值。这个值等于接收方缓冲区中剩余可用空间的大小。
  2. 动态调整
    • 如果接收方应用处理数据很快,缓冲区空间充足,rwnd 就会变大,允许发送方发送更多数据。
    • 如果接收方应用处理数据很慢,缓冲区被快速填满,rwnd 就会变小,迫使发送方降低发送速率。
  3. 遵守限制 :发送方必须严格遵守接收方通告的 rwnd,确保在任何时刻,已发送但未收到确认的数据量不超过 rwnd 的大小。

特殊情况处理

在流量控制过程中,可能会遇到两种特殊情况,TCP 协议也设计了相应的机制来应对。

零窗口 (Zero Window) 与持续计时器

当接收方缓冲区被完全填满时,它会向发送方通告一个 rwnd = 0 的窗口,即"零窗口"。这意味着发送方必须暂停发送数据。

这会带来一个潜在问题:如果后续接收方缓冲区空出空间,但通知发送方"窗口已打开"的 ACK 报文在传输中丢失了,那么发送方会一直等待,接收方也一直在等待,形成死锁

解决方案:持续计时器 (Persist Timer)

为了解决这个问题,发送方在收到零窗口通告后,会启动一个"持续计时器"。计时器到期后,发送方会主动发送一个特殊的零窗口探测报文(ZWP, Zero Window Probe),强制接收方回复当前的窗口大小。通过这种周期性的探测,可以打破死锁,一旦接收方缓冲区有空闲,就能及时通知发送方恢复传输。

糊涂窗口综合征 (Silly Window Syndrome)

这是一种性能下降的现象。当接收方应用处理数据极慢,每次只读取几个字节时,如果接收方每次都立即通告这个很小的窗口(例如 4 字节),发送方就会被迫发送大量只包含几个字节数据的"小报文"。由于每个报文都带有完整的 TCP/IP 头部(通常 40 字节),这会导致网络带宽被大量头部信息浪费,传输效率极低。

解决方案

通常采用 Clark 算法来避免此问题。其核心思想是:接收方不要一有空间就通告窗口,而是等到缓冲区有足够空间(例如,可以容纳一个最大报文段 MSS,或者缓冲区空间的一半)时,再通告一个较大的窗口。这样就避免了发送方发送大量低效的小报文。

Nagle 算法 的规则非常简单粗暴,它规定:在同一个 TCP 连接中,任意时刻,最多只能有一个未被确认的"小数据包"在网络上飞行。

这里的"小数据包"指的是长度小于 MSS(最大报文段长度,通常为 1460 字节)的数据包。

基于这个规则,发送方在发送数据时会遵循以下逻辑:

  1. 立即发送的情况

    • 如果数据量足够大(达到 MSS),直接发送。
    • 如果当前网络上没有任何未被确认的小数据包(即之前的包都已经收到 ACK 了),那么当前这个小包可以立即发送。
  2. 缓存等待的情况

    • 如果网络上已经有一个 未被确认的小数据包,且当前要发送的数据也是小包(< MSS),那么发送方不能立即发送。
    • 必须把新数据暂存在发送缓冲区中,等待之前那个小包的 ACK 回来,或者等缓冲区里的数据攒够了 MSS 大小,再一起发送。

Clark 算法与 Nagle 算法的区别

特性 Clark 算法 Nagle 算法
作用位置 接收方 发送方
解决痛点 接收方处理太慢,导致通告的窗口太小 发送方产生数据太慢,导致发送的包太小
核心手段 拖延通告:不立即通知窗口更新,等空间攒够了再说 攒包发送:把多个小数据合并成一个大包再发
目标 避免接收方通告"1字节窗口" 避免发送方发送"1字节报文"
相关推荐
@insist1231 小时前
网络工程师-交换机核心配置完全指南
运维·服务器·网络·网络工程师·软考·软件水平考试
handler011 小时前
Linux基础知识(1)
linux·服务器·c语言·开发语言·数据结构·c++
@insist1231 小时前
网络工程师-路由器与动态路由协议配置全解
网络·智能路由器·网络工程师·软考·软件水平考试
齐潇宇1 小时前
LVS 基线检查与安全加固指南(附案例)
服务器·网络·php
ん贤1 小时前
手敲Linux命令
linux·运维·服务器
sun0077002 小时前
android的qos
网络
爱学习的小囧2 小时前
SXi LAG 链路聚合负载均衡配置全教程 | LACP 协议 + 交换机联动,新手也能落地
运维·服务器·php·负载均衡·esxi
花间相见2 小时前
【Linux进阶01】—— tmux原理与实战教程
linux·运维·服务器
有谁看见我的剑了?2 小时前
新服务器上线优化调整
linux·运维·服务器