Linux网络(十九):TCP流量控制与滑动窗口详解,超时重传和快重传到底有什么区别


◆ 博主名称: 小此方-CSDN博客 大家好,欢迎来到小此方的博客。
⭐️网络系列个人专栏: 【主题曲】计算机网络
⭐️此方的GitHub: github_此方
⭐️ 我们思考 (Rethink) · 我们重建 (Rebuild) · 我们记录 (Record)


文章目录

  • 概要&序論
  • 一、滑动窗口机制详解
    • [1.1 什么是滑动窗口?](#1.1 什么是滑动窗口?)
    • [1.2 滑动窗口的大小计算](#1.2 滑动窗口的大小计算)
  • 二、深化理解滑动窗口与面试常考问题
    • [2.1 滑动窗口的核心细节问答](#2.1 滑动窗口的核心细节问答)
    • [2.2 如果丢包了怎么办?](#2.2 如果丢包了怎么办?)
      • [1. 最左侧报文丢失(数据报文丢失)](#1. 最左侧报文丢失(数据报文丢失))
      • [2. 最左侧报文对应的 ACK 丢失(应答报文丢失)](#2. 最左侧报文对应的 ACK 丢失(应答报文丢失))
    • [2.3 矫正误区:快速重传 vs 超时重传](#2.3 矫正误区:快速重传 vs 超时重传)
  • 三、流量控制的收尾补充
    • [3.1 三次握手与数据携带与流量控制的初始化](#3.1 三次握手与数据携带与流量控制的初始化)

概要&序論

  Hello大家好,我是此方。本文将会带大家详细介绍流量控制的滑动窗口这一机制。并在深入理解滑动窗口的过程中,理解丢包重传的两种机制。好,我们开始吧。

一、滑动窗口机制详解

  我们在前面的章节中讲过,发送方和接收方"你一句、我一句"地单报文发送与确认效率太低。一般情况下,为了提升传输效率,我们会让发送方一次性发送多个报文,接收方也可以一次性接收并确认多个报文。

1.1 什么是滑动窗口?

  发送方一次向对方发送多少数据?由窗口大小 决定。

  窗口大小 指的是:无需等待确认应答(ACK)而可以继续发送数据的最大值 。

  在代码与内存结构层面,我们可以将发送缓冲区看作是一个数组 char outbuffer[N]:

  • 已发送已确认:这部分数据已经完成可靠传输,其内存空间可以被重用或覆盖。
  • 可以直接发送(暂时不接收 ACK):这部分空间即为滑动窗口的范围。
  • 待发送:尚未进入窗口范围,需等待窗口滑动后才能发送。

  滑动窗口本质上是发送缓冲区的一部分 ,你可以直接理解为由下标 start 到 end 的一段区间,即窗口大小等于 end - start。

  由于序号在发送缓冲区中是依次递增的,因此随着确认应答的不断返回,滑动窗口在宏观上是基本向右滑动 的。滑动窗口移动的本质,就是 start 与 end 指针(下标)的增加。

1.2 滑动窗口的大小计算

  滑动窗口的大小究竟由什么决定?

  暂且可以认为,滑动窗口的大小由 对方的接收能力(即收到报文中的 win 字段大小) 决定:

  • start = 报文确认序号
  • end = start + win

  如果对方反馈的 win = 0,那么滑动窗口将不移动(窗口大小变为 0 ),此时发送方停止发送数据。

  总结 :滑动窗口的本质,就是 TCP 流量控制的具体实现方案 !

  板书:

二、深化理解滑动窗口与面试常考问题

2.1 滑动窗口的核心细节问答

问题 1:滑动窗口可以向左滑动吗?

  答案是:不会! 结合确认序号的定义,确认序号表示的是"该序号之前的数据已经全部成功接收"。发送方发出的数据是连续确认的,因此滑动窗口只能向右滑动,绝对不能跳跃或倒退。

问题 2:滑动窗口的大小是固定不变的吗?

  答案是:不是! 滑动窗口的大小可以变大,可以变小,甚至可以变为 0。下一次划入的范围完全由对方的即时接收能力(通告窗口大小 win)决定。

问题 3:滑动窗口会一直向右移动导致内存"溢出"吗?

  答案是:不会! 我们可以把发送缓冲区理解为一个环形的数据结构(或环形队列)。当滑动窗口移动到缓冲区的末尾时,会自动绕回头部继续循环使用,因此不需要频繁创建新的空间或担心越界问题。

2.2 如果丢包了怎么办?

  在使用滑动窗口进行批量传输时,发生丢包主要分为:最左侧报文丢失,最右侧报文丢失,中间部分的报文丢失。以及这三种情况的排列组合。我们拿最左侧报文丢失的例子讲,另外的情况可以类推。

1. 最左侧报文丢失(数据报文丢失)

  现象 :假设发送方发送了 1001~2000、2001~3000、3001~4000 等多段数据,其中 1001~2000 的数据包在网络中丢失了。

  应对机制 :由于确认序号的含义是"确认序号左侧的报文都已经成功到达",因此即使接收方后续收到了 2001~3000、3001、~4000 的数据,它返回的 ACK 确认序号依然会全部填写的都是 1001 (表示"我依然在等待 1001 号数据")。

  滑动窗口的处理 :在未收到包含新确认序号的应答之前,滑动窗口左侧不动。因为未被确认的数据必须保存在滑动窗口内,以便随时进行重传。

2. 最左侧报文对应的 ACK 丢失(应答报文丢失)

  现象 :数据报文正常到达了接收方,但是接收方发回的某个 ACK(例如 ACK 1001)在网络中丢失了。

  应对机制 :如果后续的报文顺利到达,接收方会返回更新的确认序号(例如 ACK 2001)。

  滑动窗口的处理 :发送方收到 ACK 2001 后,可以直接将滑动窗口的左侧跨越移动到 2001 的位置。因为 ACK 2001 已经间接证明了 2001 之前的全部数据(包括 1001~2000)都已经成功被对方接收,因此部分 ACK 的丢失不会影响滑动窗口的正常工作。

2.3 矫正误区:快速重传 vs 超时重传

  针对数据报文丢失的情况,TCP 提供了两种重传保障机制:

  • 快速重传(快重传) :当发送方连续收到 3 次相同的确认应答(例如连续收到 3 个 ACK 1001)时,TCP 就会认为该报文段已经丢失,并在定时器超时前立即重发 丢失的数据段 (补发 1001~2000)。这极大地提高了传输效率。
  • 超时重传:如果在规定时间内没有触发快速重传(例如发包数量较少,无法凑齐 3 次重复 ACK),定时器超时后也会兜底触发重传。

块重传是提升效率,超时重传是兜底。

  我们的发送与接收是同时进行的。所以如上图,1000-2000的数据没有收到,于是接下来三次应答返回的确认值都是1001。主机A收到三次同样的确认值后,进行快重传。补发了1000-2000。

  第6-7次在这个操作的时间段之内。在第八次的时候,补发完成了!现在第八次发现前面全部的报文全部发送成功了!这个时候才会返回确认值是7001。然后主机A就知道了:确实是7001,确实7001前面的都发送成功了。正常向后移动。

三、流量控制的收尾补充

3.1 三次握手与数据携带与流量控制的初始化

  在探讨流量控制时,有一个非常经典的细节问题:客户端在第三次握手发送 ACK 的时候,可不可以直接连带发送数据报文?

  答案是:完全可以!

  • 为什么第三次握手可以携带数据? 因为在客户端将第三次 ACK 发送出去的一瞬间,客户端就已经认为三次握手成功建立;当服务端接收到该 ACK 的一瞬间,服务端也认为三次握手完成。因此,第三次握手附带的数据可以被服务端正常处理。
  • 为什么第一、二次握手不可以携带数据? 因为在第一次(SYN)和第二次(SYN+ACK)握手阶段,对于客户端或服务端而言,连接均未成功建立,此时无法进行正常的数据处理。

  总结:我们在三次握手协商的过程中,就已经通过报头中的窗口大小(win)得知了对方的接收能力。因此在后续正常发送报文时,就可以直接正常使用流量控制了!


好的本期内容就到这里,如果对你有帮助,还不要忘记点赞三联支持,如果有什么疑问,可以再后台私信我。我是此方,我们下期再见。bye!

相关推荐
海宇服务1 小时前
零信任架构实战:基于海宇运营商近3个月欠费次数构建自动化履约能力评估管线
运维·人工智能·架构·自动化
码上有光1 小时前
Linux进程通信——共享内存、消息队列和信号量
android·linux·运维·共享内存·通信
沫璃染墨1 小时前
《从零入门Linux系统篇(五十四):线程篇·七——互斥锁底层原理:从原子交换到线程竞争与锁实现》
linux·运维·服务器·开发语言·c++·驱动开发·系统架构
志栋智能2 小时前
超自动化巡检中的异常检测与根因分析
运维·自动化
Java后端的Ai之路2 小时前
Python进阶探索24_应用案例_linux系统的监控
linux·开发语言·python·应用·探索
吴声子夜歌2 小时前
Nginx应用与运维——Nginx HTTP模块详解(访问控制功能模块)
运维·nginx·http
网络小江2 小时前
组网第二课:X.25 与帧中继——第一次让带宽“拼车“
网络协议
H.莓飛2 小时前
【数据结构】队列_OJ题
linux·数据结构·centos
H.莓飛3 小时前
【数据结构】栈_OJ题
linux·数据结构·算法·centos