计算机网络 20:为什么缓冲更多反而更慢,bufferbloat、队列管理与 ECN
下载一直有进度,交互请求却迟迟没有响应,这两种现象可以同时发生。出口持续发送并不说明新到的短报文很快就能通过:如果前方积累了大量数据,吞吐接近瓶颈容量时仍可能有很长的等待。 本篇承接第 19 篇的发送窗口与共享瓶颈,在相同限速出口下比较 FIFO 和 FQ-CoDel。实验需要区分吸收短暂突发的缓冲与长期积压,并观察拥塞信号如何返回发送端。 缓冲容量不是转发容量 设理想出口每秒服务 5,000,000 bit,前方已有 625,000 B 等待,且不考虑其他调度、协议开销或突发许可。仅把这些字节送出就需要一秒。把存储空间扩大一倍不会把出口变成每秒一千万 bit,只会允许保留更多尚未服务的数据。 123from fractions import Fractionassert Fraction(625000 * 8, 5000000) == 1assert Fraction(62500 * 8, 5000000) == Fraction(1, 10) 这道题计算的是给定积压对应的理想服务时间,不能直接拿内核的某个缓冲参数代入,便当作真实 RTT。实际路径还有反向传输、端点调度、报文大...
计算机网络 19:谁限制发送速度,cwnd、rwnd、慢启动、拥塞避免与公平性
接收程序一直读取,发送程序也一直有数据,为什么一条 TCP 连接仍不能任意提高发送速度?另一条连接加入后,第一条连接的吞吐为什么会变化?第 18 篇的接收窗口只能解释接收端限制,不能单独解释网络中的共享瓶颈。 本篇先把窗口与速率分开,再用固定限速出口比较一条和两条连接。前置是第 01 篇的 RTT 与带宽时延积、第 17 篇的重传依据,以及第 18 篇的流控。队列管理与 ECN 的对照实验留到第 20 篇。 两个窗口约束同一发送方向 接收端通告 rwnd,发送端维护 cwnd。前者表达接收限制,后者用于约束向网络注入的数据。RFC 5681 §2–3.1区分这两个量;在讨论普通新数据发送、暂不展开恢复期间额外规则时,需要同时考虑二者。 设当前 cwnd=12000 B、rwnd=8000 B,已经发出但尚未确认的数据为 6000 B。忽略回绕、SACK 恢复、分段和发送节奏等细节,可用于新增数据的余量为 max(0, min(12000, 8000)-6000)=2000 B。这是一道窗口记账题,不是完整内核发送算法。 窗口为八千字节,不意味着每秒八千字节。同样的窗口经过不同 R...
计算机网络 18:接收方读得慢会怎样,接收窗口、背压、零窗口与缓冲区
服务端暂停读取 socket,客户端为什么还能发送一段时间,随后才停下来?恢复读取后,传输又为什么能够继续?应用调用、两端内存缓冲与 TCP 通告窗口之间存在多个不同的进度,不能用“对端不读,所以本次写立即阻塞”概括。 第 15 篇解释了字节序号和确认号。本篇把窗口放回同一序号空间,沿着“停读、缓冲积累、零窗口、恢复读取”的路径观察背压。窗口是接收限制,不是链路带宽;拥塞窗口与网络瓶颈的关系留给第 19 篇。 ACK 推进与应用读取是两回事 TCP 可以先把接收字节放入内核缓冲并确认,应用稍后才读取。ACK 前进说明传输层连续接收进度,并不代表应用已经处理这些字节。应用暂停 recv() 后,只要接收端仍有可以接纳数据的空间,传输不必立刻停止。 RFC 9293 §3.8.6把通告窗口定义为接收端准备接收的序号范围。接收端在报文中给出的窗口值,应与同一报文的确认号一起解释;只比较两次窗口字段大小,容易把窗口宽度变化误认为右边界后退。 设一个无回绕算例中,接收端原先通告 ACK=1001、窗口=4096,右边界为 5097。随后接收 2048 字节,应用仍未消费,通告 ACK=30...
计算机网络 17:何时重传才合理,RTT 估计、RTO、快速重传与恢复
一个已发送的数据段迟迟没有得到确认,应该再等多久?立刻重发会把正常延迟当成丢失;一直等待又无法从真正丢包中恢复。发送端看到的是确认进度和时间,不是网络内部每个队列的完整情况。 第 15 篇定义了序号与累计确认,第 16 篇区分了连接状态和应用结果。本篇讨论发送端根据什么证据决定重传。超时、重复 ACK 和现代丢失检测各有条件,不能把抓包工具显示的“重传”直接当成某个内核分支已经被证明。 没有确认不等于数据一定丢了 同一段数据迟迟没有确认,可能是数据在去程丢失,也可能是确认在回程丢失,或者任一方向发生了排队延迟。接收端还可能采用延迟确认。只在发送端观察不到 ACK,无法在这些解释之间作唯一选择。 设发送时间为零,原始段于 80 ms 到达接收端,但确认丢失;发送端在 200 ms 重发,随后收到覆盖该数据的 ACK。接收应用可能早已取得数据,而发送端直到重发后才确认完成。这是一个假设时序,用来说明观察不充分,不是本篇实测延迟。 重传也不能代替应用层幂等设计。TCP 在同一连接的字节流中处理重复数据,上层在连接失败后重新发起一次业务请求,仍可能造成重复操作。跨连接请求标识、执行结果和...
计算机网络 16:TCP 连接何时存在,握手、半关闭、RST、TIME_WAIT 与重启
程序调用 close() 后,为什么连接条目还可能留在系统里?服务端读到 b'',为什么仍然能够返回应答?这两种现象并不矛盾:应用对象、文件描述符、TCP 端点状态与两个传输方向,不是同一个生命周期。 第 15 篇核对了字节序号、累计确认和 FIN 的序号占用。本篇把观察点扩展到 socket 调用、报文以及内核状态,分别复现正常关闭、半关闭和复位。握手成功只证明相应连接阶段完成,不能替代业务请求验收。 连接状态保存在端点 TCP 连接不是链路上一个持续存在的报文。通信两端需要保存本地与远端地址和端口、序号、窗口、计时器以及连接状态;网络中的报文推动这些状态变化。两端可能处于不同状态,某一时刻的单端列表不能代表远端已经同步到同一阶段。 RFC 9293 §3.3.1–3.3.2定义了相关状态变量与状态机。一个监听 socket 可以接受多条连接,监听状态不等于每条已接受连接的状态。排障时至少要区分监听端口、某个已连接四元组和应用持有的对象。 Python socket 对象是应用访问接口。应用关闭对象后,内核仍可能为协议收尾保存状态;反过来,对象还存在也不证明对端可达或下一次收发...
计算机网络 15:TCP 怎样标识一条字节流,序号、累计 ACK、重组与 SACK
一个 TCP 段携带四字节数据,接收端为什么可能仍返回与之前相同的 ACK?如果把确认号机械地写成“本段 seq 加长度再加一”,就无法解释数据前面存在缺口的情况。确认号描述连续接收进度,并不只是对当前报文长度做算术。 第 14 篇用按块编号的教学协议组合了确认、重传、窗口和去重。本篇转向真实 TCP:编号单位变成字节,确认语义也不能直接照搬逐块 ACK。连接状态迁移留给第 16 篇,这里只分析建立、传输和关闭过程中相关的序号占用。 编号属于一个方向的字节序列 TCP 是双向通信。一条连接中,两个方向分别维护发送序号与接收进度,不共享一个全局计数器。客户端发出的 ACK 确认服务端方向的数据。计算客户端还有多少已发字节未被确认,则需要服务端返回的 ACK 和客户端发送状态。 RFC 9293 §3.4定义了序号空间。数据按字节计数,SYN 与 FIN 各占一个序号,纯 ACK 不占。对一个段,序号空间中的占用长度可以写成: 12占用长度 = 数据字节数 + (SYN ? 1 : 0) + (FIN ? 1 : 0)段后边界 = (SEQ + 占用长度) mod 2^32 “段后边...
计算机网络 14:怎样在不可靠信道上传完整内容,ARQ、序号、计时器与滑动窗口
接收端已经得到某块数据,但返回的确认丢了,发送端应该怎么办?不再发送,可能遗漏真正丢失的数据;再次发送,又可能让接收端重复处理。仅靠发送一次或固定重发几次,都无法同时说明完整性与重复交付问题。 第 13 篇展示了 UDP 数据报边界不提供可靠交付。本篇把数据块、确认、计时器、窗口和接收缓存组合成一个有界教学协议。实验采用确定性事件信道,不发送实际网络报文;它不是 TCP,也不声称实现 TFTP。 先定义成功和允许失败的条件 输入是有限字节串,按固定方式划成有限块,每块有唯一编号。接收成功要求按照原顺序输出相同字节,不能少块、重复交付或靠最终排序掩盖已经发生的错误处理。发送成功则要求全部块都收到有效确认。 这两个状态需要分别记录。接收端拿齐内容时,最后一个 ACK 仍可能丢失;发送端因而不能立即知道接收成功。协议应允许接收端继续回应重复数据,同时让发送方在有界尝试后明确失败。永久故障下,不能承诺总能完成传输。 本篇只处理同一传输内的固定编号,不考虑进程重启、旧会话报文、序号回绕和恶意输入。实际协议需要传输身份、生命周期和资源限制,不能把本例的整数编号直接用于无限运行的服务。 确认必...
计算机网络 13:UDP 交付了什么,数据报、端口、校验与应用责任
应用连续发送编号 0 到 4 的五条消息,接收端为什么可能得到 0,3,2,4,4?这既包含缺失,也包含乱序和重复。若每次接收仍得到一条完整消息,是否就说明传输可靠?数据报边界与交付保证是两个不同的问题。 第 02 篇解释了 TCP 字节流需要应用划分消息,第 09 篇说明大小还受路径 MTU 约束。本篇使用本机 UDP socket 和一个专用应用代理,主动改变转发序列。实验发送真实 UDP 数据报,但故障来自代理代码,不代表内核自然丢包或公网故障概率。 一次发送留下什么边界 RFC 768定义 UDP 数据报服务。UDP 首部含源端口、目的端口、长度和校验和,每项为十六位;长度包含八字节首部与数据。端口必须放在目的 IP 地址等上下文中解释,不能把一个端口号视为全球唯一的服务身份。 12IP 头部 | 源端口 目的端口 UDP长度 校验和 | 应用数据 <---------- UDP 首部8字节 ----------> 发送两个数据报,并不等于向接收端提供一段可以任意切分的连续字节流。接收接口一次取一个数据报的内容,不把后一个数据报拼到前一...
计算机网络 12:跨自治系统为什么不只选最短路,BGP、策略、通告与撤回
同一个目的前缀,一条候选路径只经过一个自治系统,另一条经过两个,为什么仍可能选择后者?若物理连接一直存在,删除一条导出策略为什么又可能让某个邻居失去路由?这两个问题都不能只用链路成本解释。 第 11 篇在统一成本的小图上讨论内部选路。本篇引入独立管理的自治系统,以及各自决定接收、选择和通告哪些路径的策略。实验完全离线,不建立 BGP 会话,也不连接公网邻居。 先区分地址前缀与自治系统路径 IP 转发面对的是目的地址和前缀。BGP 通告在网络可达信息之外携带路径属性,AS_PATH 是其中之一。目的前缀回答哪些地址属于这条路由,AS_PATH 描述路径涉及的自治系统信息,二者不能互换。 RFC 4271 §5.1.2规定 AS_PATH 的形式与修改规则。本篇只使用有顺序的 AS_SEQUENCE,不处理聚合产生的其他形态。简化例子中,C 起源前缀并向外通告,邻居看到路径 [C];B 将从 C 学到的路径通告给 A 时,添加自己的 AS,A 看到 [B,C]。 这个列表不是 IP 报文逐跳携带的完整源路由,也不能直接换算成路由器跳数或物理距离。一个自治系统内部可能有多个转发节点。即...
计算机网络 11:一个自治系统内怎样选路,距离向量、链路状态、收敛与环路
一条链路断开后,剩余拓扑仍有可用路径,为什么报文可能暂时在两个路由器之间往返?最终最短路径存在,并不意味着各节点已经同时知道变化,也不意味着它们同时安装了相容的转发状态。 第 10 篇区分计算与安装。本篇把这个区别扩展到多个节点,用同一张三节点图比较两类信息传播方式:距离向量交换到目的地的距离,链路状态传播拓扑信息。实验是有界、确定性的教学模拟,没有运行 RIP 或 OSPF 守护进程。 先固定拓扑与故障 设无向链路 A-B 的成本为 1,B-C 为 1,A-C 为 5,目标是 C。这里的成本是算法输入,不是测得的时延、丢包率或带宽倒数。 1234 1 1A ───── B ───── C ╲ ╱ ╲──── 5 ────╱ 断链前,A 经 B 到 C 的成本为 2,比直接到 C 的 5 小;B 直接到 C 的成本为 1。删除 B-C 后,稳定答案应为 A 直接到 C,成本 5;B 经 A 到 C,成本 6。两种算法比较的是同一个删除事件,不能给其中一种额外保留一条链路。 这个最终答案可以手算,也可以在完整新图上计算。但分布式更新中,每...














