斯坦福-CS144-计算机网络笔记-全-

斯坦福 CS144 计算机网络笔记(全)

课程P1:互联网与IP协议简介 🌐

在本节课中,我们将学习互联网的整体概述及其基本工作原理。我们将探讨互联网的设计原则、其核心的四层模型,并深入了解让互联网得以运行的网络层协议——IP协议。课程结束时,你将能够解释互联网是什么、IP地址如何工作,并能使用工具来观察自己电脑的网络活动。

互联网概述与设计原则

互联网是一个全球性的网络系统。它并非凭空出现,而是基于一系列被广泛接受的设计原则构建的。理解这些原则,有助于我们明白互联网为何如此设计,以及它的优点和缺点。

上一节我们介绍了课程目标,本节中我们来看看互联网的核心设计理念。以下是三个关键的网络设计原则:

  • 分层:将复杂的网络功能划分为多个独立的层次,每一层只专注于特定的任务,简化了设计和维护。
  • 封装:数据在从高层向低层传递时,每一层都会在数据前加上自己的“头部”信息,就像给信件套上信封。
  • 分组交换:数据在传输前被分割成一个个小的“数据包”,每个包独立通过网络传输,最终在目的地重新组装。

这些原则共同构成了互联网可靠、高效运行的基础。

互联网四层模型

基于分层原则,互联网通常被描述为一个四层模型。这个模型是理解网络如何协同工作的框架。

上一节我们了解了设计原则,本节中我们来看看具体的分层结构。互联网四层模型包括以下层次:

  1. 应用层:最顶层,直接面向用户。像网页浏览器、Skype、BitTorrent这样的应用程序就在这一层工作。
  2. 传输层:负责在应用程序之间建立端到端的通信。最著名的协议是传输控制协议
    • 代码示例TCP (Transmission Control Protocol)
  3. 网络层:负责将数据包从源主机路由到目标主机。这一层的核心协议就是互联网协议
    • 公式/代码示例IP (Internet Protocol)
  4. 链路层:负责在单个网络链路上(如你的家庭Wi-Fi)传输数据帧。

你可以更改其他层的实现,但要接入互联网,必须在网络层使用IP协议。它是将整个互联网粘合在一起的“粘合剂”。

深入网络层:IP协议

网络层,特别是IP协议,是互联网的“邮政系统”。它负责根据地址将数据包送达目的地。

上一节我们介绍了四层模型,本节中我们重点看看核心的网络层。你将学习到:

  • IP协议的作用:为每一台联网设备分配一个唯一的IP地址,并基于此地址为数据包选择传输路径。
  • IP地址的分配:IP地址由专门的机构进行分配和管理,确保全球唯一性。
  • 数据包的路由:互联网上的路由器会检查每个数据包的目标IP地址,并决定将其转发到哪条路径,最终送达目的地。

例如,当你请求一个网页时,你的计算机会将请求分割成多个数据包并发送出去。互联网中的路由器会根据包中的目标IP地址,各自独立地决定如何转发这些包,使它们最终到达Web服务器。

实践:观察网络活动

理论学习之后,我们可以通过软件工具来直观地验证和应用所学知识。

上一节我们探讨了IP协议的工作原理,本节中我们来看看如何观察它。市面上有许多网络工具可以帮助你检查电脑如何使用互联网,例如数据包捕获分析工具(如Wireshark)或命令行工具(如ping, traceroute)。使用这些工具,你可以看到真实的数据包、IP地址以及数据包的传输路径。


本节课中我们一起学习了互联网的基本概念、其分层设计原则以及核心的四层模型。我们深入探讨了网络层的IP协议,了解了IP地址和路由的基本原理。最后,我们还介绍了可以通过实践工具来观察和验证这些网络行为。这些知识是理解现代网络通信的基石。

课程 P10:字节序详解 🧠

在本节课中,我们将学习计算机中一个重要的底层概念——字节序。我们将了解什么是大端序和小端序,以及如何通过实际的内存数据来识别它们。


概述

字节序描述了多字节数据(如整数、浮点数)在内存中存储时,字节的排列顺序。理解这个概念对于进行底层编程、网络通信和数据分析至关重要。

上一节我们介绍了数据在内存中的基本表示,本节中我们来看看字节的具体排列方式。


什么是字节序?

计算机内存以字节为单位进行寻址。当一个数据(例如一个32位整数)需要多个字节存储时,就产生了“哪个字节在前,哪个字节在后”的问题。这就是字节序。

主要有两种字节序:

  • 大端序:数据的最高有效字节存储在最低的内存地址
  • 小端序:数据的最低有效字节存储在最低的内存地址

我们可以用一个简单的比喻来理解:如果把一个多字节数据看作一个单词(例如“ABCD”),那么大端序就像我们正常的书写顺序,从左(A,最高位)到右(D,最低位)存放。而小端序则像是把这个单词倒过来写,从右(D,最低位)到左(A,最高位)存放。


如何判断字节序?

以下是一个判断字节序的示例。假设我们要存储一个32位的十六进制数 0x12345678

在内存中的存储方式对比:

内存地址(由低到高) 大端序存储内容 小端序存储内容
0x1000 0x12 0x78
0x1001 0x34 0x56
0x1002 0x56 0x34
0x1003 0x78 0x12

从上表可以看出:

  • 大端序更符合人类阅读习惯,从起始地址读出的就是数据的最高位 0x12
  • 小端序则相反,从起始地址读出的是数据的最低位 0x78

核心概念与示例

理解字节序的关键是抓住“有效字节”和“内存地址”的关系。我们可以用一段C语言代码来演示如何检测当前系统的字节序。

#include <stdio.h>

int main() {
    int num = 0x12345678;
    char *byte = (char *)# // 获取num的起始地址(低地址)

    if (*byte == 0x78) {
        printf("当前系统为小端序 (Little Endian)\n");
    } else if (*byte == 0x12) {
        printf("当前系统为大端序 (Big Endian)\n");
    } else {
        printf("无法判断\n");
    }
    return 0;
}

代码解释:

  1. 我们定义了一个整数 num,其十六进制值为 0x12345678
  2. 通过 (char *)&num 获取该整数在内存中起始地址(最低地址)的一个字节。
  3. 检查这个字节的内容。如果是 0x78(原数的最低有效字节),则为小端序;如果是 0x12(原数的最高有效字节),则为大端序。

字节序的应用场景

了解字节序后,它在哪些地方尤为重要呢?以下是几个关键的应用场景:

  • 网络通信:不同的机器可能使用不同的字节序。为了确保数据能被正确解析,网络协议(如TCP/IP)规定使用大端序作为网络字节序。数据在发送前需要转换为网络字节序,接收后再转换回主机字节序。相关的函数是 htonl(), ntohl() 等。
  • 文件格式与数据解析:许多文件格式(如图片、音频、特定数据文件)会明确规定其数据的字节序。在解析这些文件时,必须按照规定的字节序来读取数据,否则会得到错误的结果。
  • 底层系统编程:在与硬件直接交互、处理内存映射或进行反汇编/调试时,必须清楚当前环境的字节序,才能正确解释内存中的数据。

总结

本节课中我们一起学习了计算机体系结构中的字节序概念。

我们首先明确了字节序的定义,即多字节数据在内存中的字节排列顺序。然后,我们深入分析了大端序和小端序这两种主要模式的区别:大端序将最高有效字节存于低地址,小端序将最低有效字节存于低地址。通过一个具体的内存布局表格和一段C语言检测代码,我们巩固了对这一概念的理解。最后,我们探讨了字节序在网络通信、文件解析等实际场景中的重要性。

掌握字节序是深入理解计算机如何工作的关键一步,它将帮助你在进行系统级编程和跨*台开发时避免许多隐蔽的错误。

课程 P100:以太网技术详解与实践 🖧

在本节课中,我们将系统性地学习以太网技术。从它的历史起源、核心工作原理、帧结构,到其速度的演进、物理层标准的变迁,以及现代网络中至关重要的以太网交换机技术。我们将深入浅出地解析每一个概念,帮助你构建完整的以太网知识体系。

以太网的起源与核心概念 🔍

上一节我们了解了CCD,接下来我们来看看以太网。以太网始于1970年代早期,最初以每秒10兆比特的速度运行,但此后已进化得很远。首先,CCD是以太网如何工作的核心,并决定了有多少主机可以共享同一根电缆。我们将看到随着速度的提高,它变得越来越不重要。

原始的以太网看起来像这样。这些是鲍勃·梅特卡夫绘制的两幅图片,他是以太网在七十年代初期的共同发明人之一,当时他在Xerox Park工作。他后来创立了三家公司。在左边显示了他们最初设想的网络拓扑,包括有线和无线以太网。在右边显示了第一个以太网网络的具体细节。有一根大而厚的黄色电缆,它总是黄色,非常厚且刚性。这些电缆会在天花板、墙壁或地板下蜿蜒曲折。这些大的水龙头会被拧入电缆中,以建立接口的电气接触,然后连接一台电脑。随着时间的推移,它变得简单得多。

以太网帧格式 📦

了解了以太网的物理形态后,我们来看看数据是如何被封装和传输的。这是以太网帧格式,这是放在链接上的帧格式。

以下是帧格式的详细构成:

  • 前导码:第一个位位于左侧,它以前缀开始。前缀是一串一和零,只是为了训练时钟恢复电路,帮助它们开始并恢复时钟。
  • 起始帧定界符:在数据实际上开始到达之前,有一个起始帧分隔符。这是一个特殊的符号,它告诉我们数据包即将开始。
  • 目的地址:然后我们进入目的地地址。这是一个四十八位的地址,是接口制造商分配的全球唯一地址。一比特告诉我们是否是单播或多播,并且一个位可以被用来定义一个本地地址,尽管这在实际上非常不寻常。有四个六位在那里来定义全局唯一的地址,因此,以太网的地址数量非常大。
  • 源地址:使用源地址就是发送帧的本地主机的地址。
  • 类型字段:在通常的意义上,类型字段指示我们将在数据中找到什么。例如,以太类型的十六进制值 0x0800 告诉我们这里有IP在里面,这当然很常见。
  • 数据与填充:你记得任何CCD基本网络都有一个最小大小,一个最小包大小。所以我们填充包,如果数据很短,我们填充它以确保有足够的字节,以便在我们发送完数据包之前可靠地检测到碰撞。因此它们被填充到至少46个数据字节。如果数据的数量超过46,那么当然它就不会填充它,否则它会填充它只是为了确保有足够的。
  • 帧校验序列:最后,有一种被称为循环冗余检查CRC的东西,或者帧检查序列。CRC正在检查序列,使用像我们在错误检测视频中看到的代码,那将告诉我们是否有位错误,例如,如果位在电线或传输主机处理之前被损坏。

物理层标准演进 📈

理解了数据帧的结构,我们来看看承载这些帧的物理介质是如何发展的。原始的十兆比特每秒以太网由IEEE标准化,它遵循IEEE 802.3的标准。你经常会听到以太网被称为802.3网络。这只是用于编写标准的组织名称,定义了以太网正确操作的规范。

它实际上有两个组成部分:它包含了我们刚刚看到的MAC协议和帧结构,然后在下面有不同的物理层选项可以被使用。

以下是主要的物理层标准:

  • 10BASE-5:最初有一种被称为10BASE-5的,那就是之前描述的那根大厚黄色的电缆。这种电缆已经过时很长时间了。
  • 10BASE-2:然后它被一种使用同轴电缆的薄型同轴电缆版本所取代,类似于我们为电视使用的RF电缆。
  • 10BASE-T:但是,当它开始使用这种类型的电缆时,以太网真正发生了变化。这是我们都非常熟悉的RJ45电缆。那是因为它可以使用的电缆类型以及网络的拓扑结构。它开始运行在语音级别的无屏蔽双绞线上,这在许多建筑物的墙壁中都已经存在。它被称为三类电话电缆,是一种相对低质量的电缆,用于将电话连接到交换机。
  • 10BASE-F:还有一种被称为10BASE-F的光纤版本,它最初主要由军事使用,因为他们更难被窃听。有两根光纤,一根用于每个方向。

10BASE-T与星型拓扑的崛起 ⭐

以太网真正起飞,当10BASE-T标准出现用于在双绞线中运行以太网时。每秒10兆比特被传输在已经存在于世界上几乎每个建筑物中的三类双绞线电话线上。

它们被排列成星形拓扑。那些双绞线电缆将连接到配线间。不仅双绞线电缆确实帮助以太网成功,而且这种拓扑结构,即通过双绞线将终端主机连接到集线器,起到了关键作用。

集线器是一个中继器。它将接收到的所有信号,然后重复在每条出口的电缆上,除了它进入的那个。所以它实际上没有理解数据包,它只会电学上重复它们。如果有碰撞,那么碰撞将发生在这里的任何地方,它将被检测到,并且交换机将确保电压水*足够以确保它可以被检测到。

此外,这种在中心化的管理方式中,在这个枢纽,由网络管理员进行管理。这一中央管理,与其在底层进行分布式爬虫管理,不如在配线间安装使它管理以太网更加方便得多。一旦这些枢纽被放置在这些中心位置,这就导致了以太网在二十世纪八十年代中期的巨大增长。

速度提升与设计挑战 ⚡

人们想要使以太网越来越快,所以从每秒十兆比特逐渐增加到每秒一百兆比特,然后到每秒吉比特,而且最*每秒十吉比特,比原始以太网规范快一千倍。

当我们增加以太网的速度时,我们必须解决的问题是:如果我们在使用CSMA/CD,那么我们需要确保我们保持这个要求:p / r >= 2 * l / c。换句话说,数据包的持续时间比往返时间长,以便我们可以确保我们还在传输数据包当碰撞被检测到。

所以当我们增加网络的速度 r 时,为了使这个不等式成立,我们需要要么使数据包大小 p 增大以抵消 r 的增加,要么找到其他方法来*衡,或者我们需要让电缆长度 l 变小。

这就是在以太网速度加快时做出的设计选择。解决方案是保持包大小不变。因为如果我们将包大小从64字节增加到640字节,许多我们想要发送的包都将小于那个,像TCP ACK和DNS查询那样的事情,因此这将非常低效。

所以决定保持 p 不变,但是将 l 减小。百兆比特每秒以太网、千兆比特每秒以太网都有这个要求,那就是 l 的限制只有一百米。以太网交换的引入使得这变得容易得多。

快速以太网与千兆以太网 🚀

随着我们越来越快,以太网MAC协议没有改变,那就是框架结构和我们决定何时发送数据包的方式,那段一直没有变化的线。

并称为快速以太网的一百兆比特每秒以太网现在似乎不再那么快。物理层的标准有两个:100BASE-TX,这是一种用于双绞线电缆的编码结构;以及100BASE-FX用于光纤传输。它再次使用五类电缆,和我们见过的同一种RJ45连接器。它实际上开始成为全双工,这意味着电缆中使用了两对而不是只一对线对,一对线对用于在每个方向上每秒传输一百兆比特。它开始使用4B5B编码,我们视为引入时钟恢复过渡的手段。它的距离限制在一百米。

后来出现了千兆以太网标准,有1000BASE-T和1000BASE-FX。1000BASE-T标准也运行在五类电缆上,使用RJ45连接器。当今出售的笔记本电脑和服务器中,它们的以太网速度为一千兆比特每秒。在一根五类电缆上传输一千兆比特每秒的信号非常困难,所以他们实际上在电缆内部使用四对线,并且可以同时在所有四对线上传输信号。这是一种非常复杂的编码,它使用了五级信号,因此,不再只是使用二进制开闭。与以前相同,距离限制为100米。

从集线器到交换机的演进 🔄

到二十世纪八十年代末,基于10BASE-T的以太网非常流行。对于100兆比特每秒以太网的工作已经在进行中,并且显而易见,网络将会越来越快。配电间的集线器中继器意味着网络可以非常庞大,并且正在大规模部署。

但是,也清楚地表明对于越来越快的网络,每个部分都打算变得极其短,仅仅一百米。所以,许多主机共享一个小型网络。网络倾向于被它们看到的碰撞数量所淹没,因为网络上有太多的主机都在试图在同一个网络上讲话。

因此,尝试分割这些以太网网络变得自然,以减少碰撞的数量,通常被称为减少碰撞域。同时,交换硬件的成本正在下降,它变得更容易构建ASIC或专门化的芯片来做交换。因此,所有这些事情一起导致了使用以太网交换机分割网络的趋势。

以太网交换机的工作原理 ⚙️

所以,如果有一个集线器或中继器,每当一个数据包被发送,所有这些链接的中间介质都将变得繁忙并被占用。在这个圈子里,整个容量大约是每秒十兆比特或一百兆比特,取决于速率。在大型网络中,假设有数百个终端主机都连接到一个集线器或一组集线器,这将对他们的总容量使用非常有限。

如果我们允许同时进行几通通信,例如,如果A想要跟B谈话,同时在C正在跟D谈话,因为他们正在与不同的主机集交谈,为什么我们不允许这样通过允许通信独立进行?所以,而不是像电信号一样,集线器只是重复信号,如果它能够实际解析数据包,只将数据包发送到正确的目的地,就像路由器一样,但是根据以太网地址而不是IP地址。这被称为以太网交换机,有时也被称为网桥。

以下是交换机的基本操作:

  • 并发通信:如果A发送给B,数据包将流向交换机。交换机将查看以太网地址,决定将其发送到B。同时,也许C正在向D发送一个包,在这里也会发生同样的事情。现在碰撞仅仅局限于一根电缆中。
  • 全双工模式:在同一时间,也引入了一种叫做全双工以太网的东西,这利用了通信可以在电缆的两方进行且不会同时在同一时间碰撞的事实。因此现在,交换机可以完全无需使用CSMA/CD操作。
  • 优势:一旦引入了交换机,所有的链接都是全双工的。优势是多个并发通信,全双工链接可以同时发送和接收。还有管理上的好处,如果有死或故障的终端主机,他们可以被交换机隔离,你可以只是关闭链路,然后完全将其从网络中隔离出来,以防止它损害网络中的任何其他交换机。

交换机的转发与学习机制 🧠

以太网交换机已经成为今天将以太网部署的主要方式。它执行一些非常简单的操作:转发和学习。我们已经见过这种情况,它根据转发表转发数据包,然后根据看到的地址学习转发表的内容。

以下是其工作流程:

  • 检查与转发:当帧到达时,首先检查每个到达帧的头部以检查目的地址。如果以太网目的地址在其转发表中,它将帧转发到正确的输出端口,或者如果是广播,则转发到端口集合。
  • 广播与学习:如果以太网目的地址不在其表中,它将广播帧到交换机的所有端口,除了通过哪个端口帧到达的端口外。然后,表项由检查到达包的以太网源地址学习得到。所以它将取源地址,在表中查找,如果找不到,它将在表中填充那个说明的条目。这样,下次帧就不会广播,它会直接发送到正确的目的地。
  • 拓扑维护:然后还有拓扑维护,它运行生成树协议,交换那些被称为桥协议数据单元的东西,并运行生成树协议与其他交换机通信,以创建无环拓扑,以便它可以决定哪些端口应启用或阻塞,以确保在所有网络交换机中创建无环生成树。

现代网络中的以太网部署 🏢

这里是一个可能在大学校园中看到这种情况的例子。这就是我们的学院网络在斯坦福内部每个建筑物中的样子。这可能是一个建筑物或一个楼层的大楼。那个楼层还有一个交换机,然后它们连接到建筑物路由器,它们通常会连接到另一个在另一个建筑物中的路由器,以防止建筑物路由器失败。然后,这个路由器可能正在运行OSPF用于在校园内路由数据包。所以这些路由器形成了校园骨干,遍布我们的学院校园。然后,它们最终连接到一个BGP路由器,该路由器连接到公共互联网,以交换到外部世界的前缀和路径。

因此,以太网交换机可以连接许多主机,有时数百个主机一起,有提供数百个端口的交换机,然后连接可能建筑物中的所有终端主机,或者一个楼层的终端主机。

总结 📝

在本节课中,我们一起系统地学习了以太网技术。

介质访问控制协议有两种主要类型:随机访问和确定性。随机访问协议证明非常受欢迎,因为它们很好且简单,它们为传输主机提供了一种快速、低延迟的网络访问,当网络使用较少时。多年来,CSMA/CD已经成为最常用的简单访问协议,用于第一代10兆比特每秒的以太网。

多年来,以太网标准出现了100兆比特每秒的版本(快速以太网),然后千兆比特每秒的以太网,以及更*的10千兆比特每秒。链路长度的限制和需求更多的容量意味着CSMA/CD逐渐被以太网交换机取代。在其中,终端主机通常通过全双工链接连接,因此可以同时发送和接收。

以太网交换机基本上进行全路由,就像路由器一样,但是在以太网地址上。它们学习以太网地址来填充他们的表,通过学习通过的网络包的源地址,这样它们就可以构建一个简单的转发表。然后它们使用生成树协议来构建无环拓扑连接网络中的所有交换机。因此,以太网交换机今天无处不在。

📡 课程 P101:无线网络有何不同

在本节课中,我们将探讨无线网络,并分析其在实践中与有线网络存在显著差异的原因。我们将从无线介质的共享性、信号衰减、干扰等核心特性入手,解释为何无线连接有时会显得不稳定且性能不佳。


🌐 无线与有线的根本区别

上一节我们介绍了课程概述,本节中我们来看看无线网络与有线网络的根本区别。历史上,网络设计基于有线系统的行为模式,但将两者连接起来往往很困难,这正是Wi-Fi性能有时较差的原因。

无线系统与有线系统的主要差异在于其使用的介质。在有线网络中,介质(电线)完全处于用户控制之下,没有人与你争夺线路容量。而在无线环境中,你利用的是周围的电磁频谱,这是一个共享的、不受控制的介质。

因此,无线网络在实际操作中受到严格监管。以下是美国无线电频谱分配的示意图,它展示了从低频到高频的频谱如何被分配给不同用途。

电磁频谱范围极广,从约3千赫兹(kHz)延伸至300吉赫兹(GHz)。对于数据通信,尤其是现代接入点网络(如Wi-Fi),我们主要使用其中几个狭窄的频段。

以下是关于频谱的几个关键点:

  • 低频(如3 kHz)的波长可达数百万英尺。
  • 高频(如300 GHz)的波长可能短至一英尺的三分之一。
  • 我们今天使用的电话和笔记本电脑等设备的数据通信,主要集中在为Wi-Fi等应用设计的几个微小频段上。

📶 信号强度与衰减

理解了频谱的划分后,我们来看看无线信号的传播特性。与在线缆中传播的信号不同,无线信号是在空间中辐射的。

无线信号强度会随距离增加而衰减。最简单的模型是,如果使用一个完美的全向天线,信号强度至少按距离的*方(1/r²)衰减。这意味着,当你离发射器两倍远时,信号强度至少减弱为原来的四分之一(衰减75%)。

此外,无线环境不受控制,存在诸多变数:

  • 障碍物:如果有人或物体(如金属板)位于你和接入点之间,信号会大幅减弱。
  • 多径效应:信号可能通过不同路径(如墙壁反射)到达接收端,造成信号副本叠加,这可能导致在某些位置信号突然变差。
  • 动态变化:环境不断变化,如人员走动、门开关、湿度变化,都会导致信号强度实时波动。

为了让你感受这种变化,下图展示了一次实测数据:在静止环境下,接收信号强度(RSSI)和包接收率(PRR)在短时间内发生了剧烈波动。

可以看到,在约十秒内,链路质量从接*完美骤降至完全无法通信,这要求网络协议(如TCP及其重传机制)必须能处理此类行为。


🔄 高度动态的网络环境

信号衰减问题之外,无线网络还面临高度动态的环境挑战。下图展示了斯坦福无线接入网络(SWAN)在2.5秒内的链路质量变化。每条线代表节点间的连接,其颜色深浅表示数据包接收率。

可以观察到,链路质量在毫秒级时间内快速振荡,在高质量与低质量之间来回切换。这清晰地表明,像Wi-Fi这样的无线网络具有高度动态和不稳定的特性。


📡 干扰问题

除了信号本身的问题,干扰是无线网络的另一大挑战。许多无线通信(如家用Wi-Fi)工作在无需许可的频段上,这虽然免费且方便,但也意味着多种技术共享同一频段。

例如,在2.4GHz频段(Wi-Fi的低频段),不仅存在Wi-Fi信号(使用信道1、6、11),还有Zigbee、蓝牙等其他无线系统。这意味着802.11(Wi-Fi)设备可能会受到802.15.4(如Zigbee)设备的干扰,反之亦然。

下图展示了在真实环境中,不同Wi-Fi信道随时间变化的活跃程度。可以看到,某些信道(如1和11)非常繁忙,充满了Wi-Fi活动,这必然导致同频段设备的相互干扰。


💎 课程总结

本节课中,我们一起学习了无线网络与有线网络的核心差异。总结如下:

无线网络正变得越来越重要,但我们通常更愿意无线连接互联网,而非插入网线。然而,无线网络通常不如有线网络可靠和稳定。

这主要源于其根本特性:无线网络处于一个共享的、不受控制的介质中。许多设备竞争使用,周围环境不断变化,并且存在大量干扰。

因此,在实践中,为了使无线网络达到可用的“足够好”的状态,其底层技术采用了与有线网络完全不同的算法和协议。这意味着无线链路层无线媒体访问控制(MAC)系统的设计与有线版本截然不同。

在接下来的系列课程中,我们将深入探讨这些具体的技术差异。

📡 课程 P102:无线网络中的媒体访问控制原理

在本节课中,我们将要学习无线网络中的媒体访问控制(MAC)原理,并探讨为何在有线网络中行之有效的经典算法(如CSMA/CD)在无线环境中会失效。


🎯 媒体访问控制协议的目标

上一节我们介绍了课程主题,本节中我们来看看媒体访问控制协议的基本目标。其核心目标有三项,但无法同时完全实现,需要在它们之间做出权衡。

以下是三项核心目标:

  1. 独占性:如果只有一个节点希望传输数据,它应当能够占用信道的全部容量。
  2. 公*性:如果有多个节点试图传输,它们应当各自获得信道的公*份额。
  3. 高效性:当大量节点竞争信道时,信道应得到充分利用。例如,若每个节点仅能获得千分之一的信道容量,则效率低下。


🔌 回顾有线网络:CSMA/CD

在深入无线网络之前,我们先回顾一下有线以太网中使用的经典协议:载波侦听多路访问/碰撞检测(CSMA/CD)

其工作流程可以概括为以下步骤:

  1. 节点准备发送数据时,首先侦听信道是否空闲(通过检测线缆电压)。
  2. 若信道忙,则持续等待直至空闲,并再等待一个96位的时间(即帧间间隙)。
  3. 开始传输数据,并在传输过程中持续侦听。
  4. 碰撞检测:若发送方检测到线缆上的电压信号与其自身发送的信号不符,则判定发生碰撞。
  5. 一旦检测到碰撞,立即停止发送,并发送一个阻塞信号以通知所有节点。
  6. 执行指数退避算法,等待一段随机时间后,重新尝试发送。

这个协议的核心在于发送方能够实时检测到碰撞,因为有线信道中信号衰减很小,发送方和接收方对信道状态的感知基本一致。


❓ 为何CSMA/CD在无线网络中失效?

上一节我们介绍了CSMA/CD的工作原理,本节中我们来看看它在无线环境中面临的根本挑战。问题正出在“碰撞检测”这一步。

在无线网络中,发送方可能无法检测到发生在接收方的碰撞。主要原因在于信号随距离急剧衰减,以及发送方自身强大信号的遮蔽效应。

考虑以下场景:

  • 节点A正在向节点B发送数据。
  • 同时,远处的节点C也开始向节点B发送数据。
  • 在节点B处,来自A和C的信号相互干扰,发生碰撞,导致B无法正确接收。
  • 然而,对于发送方A而言,节点C的信号由于距离远而非常微弱,加之A自身正在发射强信号,因此A完全无法感知到C信号的存在,自然也就无法检测到这次碰撞。

用公式描述信号衰减:信号强度通常与距离的*方成反比(强度 ∝ 1 / 距离²)。因此,远距离信号在发送方处可能弱到无法识别。

所以,CSMA/CD依赖的“边发边听”碰撞检测机制在无线网络中不适用


💎 课程总结

本节课中我们一起学习了:

  1. 媒体访问控制协议的三个核心目标:独占性公*性高效性
  2. 有线网络中的经典协议CSMA/CD的工作流程,其关键在于发送方能实时检测碰撞。
  3. CSMA/CD在无线网络中失效的根本原因:由于信号衰减和自身信号遮蔽,发送方无法可靠检测到发生在接收端的碰撞。

理解这一差异是设计有效无线MAC协议(如CSMA/CA)的重要基础。

计算机网络课程 P103:CSMA/CA 原理详解 📡

在本节课中,我们将要学习无线网络中一种关键的媒体访问控制协议——载波侦听多路访问/碰撞避免。我们将探讨其工作原理、具体实现步骤以及在实际应用中面临的主要挑战。


概述

CSMA/CA 是一种在无线网络中广泛使用的 MAC 协议。由于无线信号衰减的特性,发送方无法像在有线网络中那样直接检测到数据包在接收端是否发生了碰撞。因此,该协议引入了一套机制,通过接收方的反馈来避免和应对碰撞。


CSMA/CA 的基本原理 🧠

上一节我们介绍了 CSMA/CA 的设计动机,本节中我们来看看它的核心工作流程。

其核心思想是:发送方在传输数据前先侦听信道。如果信道空闲,则等待一段随机时间后发送数据。发送后,发送方会等待接收方返回一个链路层的确认帧。如果收到确认,则认为传输成功;如果没有收到确认,则推断可能发生了碰撞或传输错误,并执行“后退”算法,等待更长时间后重试。

以下是 CSMA/CA 的关键步骤:

  1. 载波侦听:发送前侦听无线信道是否空闲。
  2. 随机后退:如果信道空闲,等待一个随机的退避时间。
  3. 数据传输:退避时间结束后,发送数据帧。
  4. 等待确认:发送后,等待接收方返回的 ACK 确认帧。
  5. 退避重试:若未收到 ACK,则执行指数退避算法,增大等待窗口后重试。

802.11 Wi-Fi 中的实现 🔧

了解了基本原理后,我们具体看看它在 802.11(Wi-Fi)标准中是如何实现的。802.11 有多种模式,其中最常见的是 CSMA/CA 模式。

发送方会选择一个初始的退避时间 T。其工作流程可以描述为以下伪代码:

初始化退避时间 T = 随机小值
循环:
    while 信道繁忙:
        暂停递减 T
    while 信道空闲 且 T > 0:
        T = T - 1
    if T == 0:
        发送数据包
        等待 ACK
        if 收到 ACK:
            传输成功,为下一个包选择新的小T值
        else:
            T = T * 2  # 指数退避
            if T > 最大阈值:
                丢弃当前数据包,处理下一个

流程简述如下:

  • 发送方持续侦听信道。
  • 当信道空闲时,开始递减退避计时器 T
  • T 减至 0 时,立即发送数据。
  • 若成功收到确认(ACK),则重置 T 为一个较小的随机值,准备发送下一帧。
  • 若未收到 ACK,则将 T 值加倍(指数退避),然后重新尝试侦听和发送。如果 T 超过某个上限,则丢弃当前帧。

这种指数退避机制有效地减少了在信道繁忙时发生连续碰撞的概率。


CSMA/CA 面临的挑战 ⚠️

尽管 CSMA/CA 非常有效,但在复杂的无线环境中,它仍然面临几个经典问题。

1. 隐藏终端问题

隐藏终端是指两个互不可见的节点(A 和 C)同时向一个都能看见的中间节点(B,如接入点)发送数据的情况。

问题描述:A 和 C 都在 B 的通信范围内,但彼此不在对方的通信范围内。当 A 向 B 发送数据时,C 侦听本地信道发现是空闲的(因为它听不到 A 的信号),于是 C 也开始向 B 发送数据,导致两个信号在 B 处发生碰撞。而 A 和 C 都无法直接感知到这次碰撞。

2. 暴露终端问题

暴露终端是与隐藏终端相反的问题。

问题描述:节点 B 向 A 发送数据,同时节点 C 想向 D 发送数据。C 能听到 B 的信号,但 D 听不到 B 的信号(即 B 和 D 互不在通信范围内)。当 C 侦听信道时,会听到 B 正在传输,因此认为信道繁忙而推迟向 D 的发送。但实际上,C 向 D 发送数据并不会干扰 B 到 A 的传输。这就导致了信道利用率下降。

3. 碰撞与信号衰减的混淆

在无线网络中,数据包丢失可能由两种原因导致:碰撞信号质量差(低信噪比)

问题描述:发送方 A 未收到接收方 B 的 ACK。A 无法区分这是因为有另一个节点 C 同时发送造成碰撞,还是因为 A 与 B 之间的信道突然变差导致信号无法正确解码。这两种原因需要不同的应对策略:

  • 如果是碰撞,应执行退避,减少竞争。
  • 如果是信号差,应降低传输速率,使用更稳健的编码。

标准 CSMA/CA 无法区分二者,可能采取错误策略,例如在信号差时不断退避,或在碰撞时错误地降低速率,反而可能加剧问题。


总结

本节课中我们一起学习了无线网络的核心协议 CSMA/CA。

  • 我们首先了解了它通过载波侦听随机退避链路层确认来避免碰撞的基本原理。
  • 接着,我们剖析了它在 802.11 Wi-Fi 中的具体实现,包括其指数退避算法。
  • 最后,我们探讨了它在实际部署中面临的三大挑战:隐藏终端暴露终端以及无法区分碰撞与信号衰减

理解这些原理和挑战,是深入学习无线网络技术和更高级 MAC 协议(如 RTS/CTS)的重要基础。

📡 课程 P104:无线网络中的 RTS/CTS 机制

在本节课中,我们将要学习无线媒体访问控制中的一种重要机制——请求发送/允许发送(RTS/CTS)。我们将探讨其工作原理、如何解决隐藏终端问题,以及它为何没有被广泛使用的原因。


🔍 RTS/CTS 机制概述

上一节我们介绍了无线网络中的基本访问控制问题。本节中我们来看看一种旨在解决这些问题的具体机制:RTS/CTS。

RTS/CTS 使用一组短的控制数据包,来确认信道是否安全以传输数据。考虑三个节点 A、B 和 C。A 能听到 B,B 能听到 C,但 A 和 C 无法听到彼此。

在 RTS/CTS 交换中,节点不会立即发送数据包。其过程如下:

以下是 RTS/CTS 交换的基本步骤:

  1. 第一步:节点 A 发送一个称为“请求发送”(RTS)的短控制包。该消息询问节点 B:“我可以发送一个持续时间为 X 的数据包吗?”
  2. 第二步:如果节点 B 成功接收到 RTS,并且认为信道空闲(例如,附*没有其他节点在传输),它将以“允许发送”(CTS)包回应。CTS 告知节点 A 可以在此时间段内发送数据。
  3. 第三步:关键点在于,节点 C 虽然听不到 A 的 RTS,但能听到 B 发出的 CTS。因此,节点 C 知道 B 即将接收数据,从而知道自己应该在该时间段内保持静默,避免传输。
  4. 第四步:节点 A 在收到 CTS 后发送数据。
  5. 第五步:节点 B 在成功接收数据后,发送确认(ACK)回传给节点 A。

这就是基本的 RTS/CTS 交换流程:RTS -> CTS -> DATA -> ACK。如果节点 A 发送 RTS 后没有收到 CTS,它可以采用标准的退避算法(例如指数退避)稍后重试。

RTS/CTS 的重点在于,它并不能完全消除隐藏终端问题,而是将数据包碰撞的风险转移到了控制包的交换阶段。例如,如果 A 和 C 同时向 B 发送 RTS,则 RTS 包会发生碰撞,但这只会导致控制包重传,而不会造成实际数据包的丢失。


⚖️ RTS/CTS 对各类问题的效果

上一节我们描述了 RTS/CTS 的工作流程。本节中我们来看看它如何应对 CSMA/CA 中常见的几个问题:隐藏终端、暴露终端以及碰撞或低信噪比(SNR)。

以下是针对每个问题的分析:

  • 隐藏终端问题:RTS/CTS 无法彻底解决此问题。例如,如果 B 发出的 CTS 包因为其他节点正在传输而未被 C 听到,隐藏终端问题仍可能发生。但 RTS/CTS 通过 CTS 包清空接收方周围的信道,极大地减少了隐藏终端问题发生的概率。
  • 暴露终端问题:RTS/CTS 在实践中对暴露终端问题帮助不大。假设 B 向 A 发送 RTS/CTS 准备传输,而 C 想向 D 传输。C 听不到 B 的 RTS 也听不到 A 的 CTS,理论上它可以向 D 传输。但实际上,C 通常不会传输,因为它之后可能会干扰 A 发回给 B 的 ACK 确认包。
  • 碰撞或低 SNR 问题:RTS/CTS 通过减少隐藏终端引起的碰撞,间接有助于缓解因碰撞导致的数据丢失。但它不能直接解决信号弱或信噪比低的问题。

综上所述,RTS/CTS 机制对解决常见的隐藏终端问题非常有帮助


💡 为何 RTS/CTS 未被主流采用?

既然 RTS/CTS 有助于解决隐藏终端问题,尤其是在网络负载较重时,那么我们为什么不始终使用它?为什么当今主流的 Wi-Fi 系统仍主要使用 CSMA/CA?

核心原因在于开销

回忆 RTS/CTS 的数据包交换流程:RTS -> CTS -> DATA -> ACK。问题在于这些控制包(RTS 和 CTS)的传输时间。

在 Wi-Fi 中,数据包可以根据信道条件使用很高的速率(如采用密集的调制星座)发送。然而,控制包(RTS、CTS)需要确保所有可能范围内的节点都能听到,因此必须始终以最低的物理层速率发送

考虑一个例子:假设网络支持 1, 2, 5.5 和 11 Mbps 四种速率。数据包可以用高速率发送,但 RTS/CTS 控制包只能用 1 Mbps 的速率发送。

以下是随着数据速率提升,开销变化的影响:

  • 在低数据速率(如 1 Mbps)下,数据包本身传输时间就长,短小的控制包带来的额外开销占比相对较小。
  • 但在高数据速率(如 11 Mbps)下,数据包传输得非常快,时间很短。而此时,以低速传输的、固定大小的 RTS/CTS 控制包在总传输时间中所占的比例显著增大,成为巨大的开销。

研究表明,在 11 Mbps 的网络上,使用 CSMA/CA 可能获得约 5.8 Mbps 的实际吞吐量,而启用 RTS/CTS 后,吞吐量可能下降至 4.4 Mbps,降低了约四分之一。如果网络本身空闲,碰撞很少,那么启用 RTS/CTS 只会带来性能损失。

因此,一种折中的方法是:在网络运行良好、丢包率低时,使用基本的 CSMA/CA;当检测到碰撞增多、隐藏终端问题严重时,再动态切换到 RTS/CTS 模式以获得更好的信道仲裁。尽管有相关研究,但出于对开销的考虑,RTS/CTS 并未成为默认的全局设置。


📝 课程总结

本节课中我们一起学习了无线网络中的 RTS/CTS 机制。我们了解了它通过 RTS -> CTS -> DATA -> ACK 的四步握手来预约信道,能有效减少隐藏终端问题。同时,我们也明白了由于其控制包必须低速传输,在高数据速率网络中会引入显著的开销,导致吞吐量下降,这解释了它未被 Wi-Fi 主流默认启用的原因。这种机制体现了网络设计中在冲突解决传输效率之间进行的典型权衡。

课程 P105:Wi-Fi (802.11) 原理详解 🛰️

在本节课中,我们将深入探讨 802.11(即 Wi-Fi)的技术细节。我们将学习其数据包格式、如何使用不同的介质访问控制算法,并对 Wi-Fi 技术有一个全面的概述。

自适应速率与调制编码方案 📶

上一节我们介绍了 Wi-Fi 的基本概念,本节中我们来看看 Wi-Fi 如何根据信道条件自适应调整速率。

Wi-Fi 标准(如 802.11n)可以在不同的速度下运行,这取决于所使用的调制和编码方案。调制编码方案索引 是数据包中的一个字段,它指明了数据部分是如何被调制和编码的。

802.11 标准使用从二进制相移键控64正交振幅调制等多种调制方式,编码率从 1/25/6 不等。

这意味着,一个 802.11n 链路的数据速率会根据观测到的信噪比进行自适应调整,范围从 6.5 Mbps150 Mbps,速度差异超过 20 倍。因此,Wi-Fi 能够根据频谱和时间的状况,在一个非常宽的速率范围内进行适配。

与有线系统相比,这是一个关键优势。因为有线介质的信噪比是固定的,所以只能以固定速度运行。而 Wi-Fi 可以根据信道条件动态调整其速率。

物理层与链路层帧结构 📡

了解了速率自适应原理后,我们来看看实现这一机制的具体帧结构。这发生在物理层和链路层。

以下是 802.11b 物理层帧的构成:

  1. 同步位:一系列用于让接收方检测并确认这是 Wi-Fi 信号(而非噪声)的位。
  2. 帧起始分隔符:一个特定的比特序列,标志着同步阶段的结束。
  3. 物理层头部:包含信号、服务、长度和 CRC 信息的字段。这部分数据会经过前向纠错编码和交织等技术处理,以抵抗比特错误。接收方必须完整无误地接收此头部,才能开始解析后续数据。

在链路层(MAC 层)帧中,包含以下主要字段:

  • 帧控制字段:提供关于帧类型和特征的控制信息。
  • 持续时间字段:指示此数据包或整个数据交换将持续多长时间。这对于虚拟载波侦听至关重要。
  • 地址字段:最多可包含四个地址,通常包括源地址和目的地址,用于实现诸如跨网络转发等功能。
  • 序列号:用于数据包排序。
  • 网络层数据:来自上层协议的数据载荷。
  • 帧校验序列:一个 4 字节的 CRC,用于检错。

关键字段:持续时间与虚拟载波侦听 ⏱️

上一节我们列出了链路层帧的各个字段,本节我们重点分析其中两个关键字段:帧控制字段持续时间字段

持续时间字段 用于告知所有能侦听到该数据包的节点(包括接收者),此次传输或后续的帧交换(如 RTS/CTS/数据/ACK)将占用信道多长时间。这样,即使其他节点因为速率太快而无法解调数据部分,它们也知道信道将在该时段内繁忙,从而避免冲突。

这里的核心机制是 虚拟载波侦听。在 CSMA/CA 算法中,节点通过物理侦听(实际载波侦听)或通过解读数据包中的“持续时间”信息(虚拟载波侦听)来判断信道是否繁忙。例如,一个 CTS 控制包中的持续时间字段,可以告诉周围节点:“信道将在接下来 X 微秒内繁忙,请勿发送”。

地址字段与链路虚拟化 🌉

除了控制信道访问,802.11 帧头中的地址字段还支持链路虚拟化功能。

通常情况下,帧中包含源地址和目的地址。但通过使用多个地址字段,可以实现更复杂的功能。例如,一个无线客户端(地址1)可以通过接入点(地址2)向有线网络上的另一台设备(地址3)发送数据。接入点就像一个网桥,利用这些地址信息将数据包从无线域转发到有线域,从而虚拟化了对有线网络的访问。

向后兼容性与开销问题 ⚖️

在了解了帧结构的功能后,我们必须面对一个现实问题:开销

由于 RTS/CTS 等控制帧以及物理层头部的存在,会产生显著的开销。在 11 Mbps 的速率下,开销可能高达 25%。这归根于 802.11 的一个基本设计矛盾:它需要支持巨大的速率范围,同时又必须保持向后兼容性

这意味着,无论实际数据传输速率多高(例如 600 Mbps),物理层头部都必须以所有设备都能理解的最低速率(例如 1 Mbps)进行发送。因为只有这样,所有监听设备(包括旧设备)才能正确解析持续时间等关键控制信息。

思考这个问题的方式是:当链路速率很慢时(如 1 Mbps),控制头部所占时间比例较小。但当数据速率变得极快时(如 600 Mbps),发送同样比特数的控制头部所需的时间虽然不变,但相对于飞速传输的数据部分,这部分“慢速”发送的控制信息会占据数据包空中时间的绝大部分。

研究表明,在以 600 Mbps 最快速率操作时,控制序列可能占据总传输时间的 92%,而仅有 8% 的时间用于发送有效数据。因此,即使数据速率翻倍,实际吞吐量的提升也微乎其微,因为绝大部分时间仍被控制开销所占据。这就是 收益递减 效应。

总结 📝

本节课中,我们一起学习了 Wi-Fi (802.11) 的核心原理。

我们了解到,802.11 使用 MCS 索引 支持基于信噪比的自适应速率调整。其帧结构分为物理层头部和链路层帧,其中 持续时间字段 实现了 虚拟载波侦听,而多个 地址字段 支持了链路虚拟化。

然而,为了实现广泛的 向后兼容性 和互操作性,必须以最低速率发送控制头部,这导致了在高数据速率下,控制开销占据绝大部分空中时间,使得实际观测到的吞吐量远低于标称的物理层速率。这是理解 Wi-Fi 实际性能的关键。

计算机网络课程 P106:分片与重组 🧩

在本节课中,我们将要学习网络通信中的一个重要概念:分片与重组。我们将了解为什么需要将大数据块分割成小片段,这个过程发生在网络的哪些层次,以及它是如何具体工作的,特别是在IP协议中。

概述

当高层的数据单元大于底层网络能够支持的最大传输单元时,就需要进行分片与重组。分片是将大数据块拆分成更小片段的过程,以便底层网络能够传输。重组则是接收方将这些片段重新组合成原始数据的过程。

分片与重组的基本问题

上一节我们概述了分片与重组的概念,本节中我们来看看它要解决的具体问题。

假设有一台名为“myth”的计算机在斯坦福大学,它想从谷歌请求一个网页。谷歌发回的HTTP响应数据包大小为10千字节。这个数据块相当大。问题在于,从谷歌到“myth”的路径上,可能存在某些网络节点无法支持传输10千字节的数据包。

事实上,以太网支持的最大传输单元在许多速率下是1500字节。因此,我需要做的是将这个10千字节的数据包分解成一系列更小的、网络能够支持的片段。

设想一个极端情况:如果我从谷歌下载一个非常大的文件,我不希望发送一个1GB大小的数据包,因为它会长时间占用通信信道。所以,我需要将数据分解成更小的块。

在这个例子中,如果以太网帧的最大尺寸是1.5千字节,我就需要将这个10千字节的数据包分成7个片段。其中前6个片段每个可以是1.5千字节,最后一个片段是1千字节。这就是分片的过程。

这些片段到达“myth”计算机后,它的任务就是进行重组,将这七个片段重新组装成原始的10千字节数据。

分片与重组发生的层次

分片与重组可以发生在网络的不同层次。

传输层
例如,它可以发生在传输层。TCP协议在将数据流分割成段时就会进行分片,这些段被传输到对端后,再被重组成一个可靠的数据流。这种重组发生在TCP端点之间,是端到端的。一旦TCP段被一个端点生成,它就是不可分割的,会完整地到达另一端。你永远不会看到一个TCP段被拆分成两个独立的段,尽管在它之下的网络层或链路层可能会将其进一步拆分。

网络层
这与TCP形成对比。在网络层,分片与重组是在主机到主机的基础上进行的。在IP协议中,一个中间节点可能会接收一个数据包并将其拆分。因此,一个IP数据包在网络中传输时,可能会在某个中间点被分解成多个IP分片,然后由最终的目的主机将这些分片重新组装成原始的IP数据包。这意味着分片可以发生在网络内部。

链路层
最后,分片与重组也可以发生在链路层。一个例子是Zigbee或802.15.4链路层,它的帧非常小,大约只有120字节(127字节是最大值,但还未包含帧头)。有时你想在这种链路上发送大的数据包,比如一个1280字节的IPv6数据包。这时,网络层会将这个1280字节的数据包传递给一个叫做“6LoWPAN”(IPv6 over Low-Power Wireless Personal Area Networks)的适配层。6LoWPAN这个链路层技术会将其分片,然后在链路的另一端重新组装成原始数据包。在这种情况下,分片纯粹发生在链路上,网络层是看不到的。

IP协议中的分片机制

现在,让我们通过一个具体例子来深入理解。IP协议中的分片机制虽然在实际中人们尽量避免使用,但其原理简单,非常适合用来解释分片是如何工作的。

假设我们有一条跨越三跳的路由路径。第一跳和第三跳使用以太网,其最大传输单元为1500字节。但中间一跳使用点对点链路,其最大传输单元为576字节。

这意味着在链路层,帧的有效载荷只能支持576字节或1500字节的数据。

现在,假设左边的主机上的某个应用程序想要发送一个1400字节的有效载荷。

  • 在第一跳,这没有问题。我们可以取这个1400字节的有效载荷,加上20字节的IP头部,总共1420字节。这完全可以放入一个以太网帧中。
  • 但当数据包到达第二个节点(路由器)时,问题出现了。我们无法将这个1420字节的IP数据包放入一个最大载荷为576字节的PPP帧中。

因此,IP协议会在这里采取行动:它将原始数据包拆分成三个分片。这个节点会接收这个1420字节的IP数据包,意识到它需要通过这个PPP链路转发,于是将其拆分成三个独立的IP数据包(稍后会展示它们是如何形成的),并分别放入三个PPP帧中,每个帧带有更小的有效载荷(例如512字节、512字节和376字节)。

关键点在于:一旦数据包在这个第二个节点被分片,这些分片在后续网络中会保持不变地传输。所以,第三个节点并不会重组它们,它只是将这些IP分片分别放入以太网帧中,然后转发给最终目的地。最终,希望目的地主机能收到所有分片,并将它们重组成原始的1400字节数据。

IP分片头部字段详解

那么,IP协议是如何实现这一点的呢?如果我们查看IP头部,其中有几个字段专门用于分片与重组。

在分片之前,我们会看到一个标准的IP数据包,其结构如下:

  • 标识符:设为某个值 x
  • 更多分片位:设为 0(表示这是最后一个或唯一的分片)。
  • 分片偏移:设为 0
  • 这是一个1400字节有效载荷的普通IP数据包。

数据包被分片后,情况发生了变化:

  • 标识符:在所有三个分片中保持相同的值 x。这允许接收方识别哪些分片属于同一个原始数据包。
  • 更多分片位:对于最后一个分片之外的所有分片,此位被设置为 1,表示后面还有更多分片到来。第一个和第二个分片的该位为 1,最后一个分片的该位为 0
  • 分片偏移:告诉接收方这个分片的数据在原始数据包中的起始位置。偏移量以8字节为单位。
    • 第一个分片:有效载荷512字节,偏移为 0(覆盖字节 0-511)。
    • 第二个分片:有效载荷512字节,偏移为 6464 * 8 = 512,覆盖字节 512-1023)。
    • 第三个分片:有效载荷376字节,偏移为 128128 * 8 = 1024,覆盖字节 1024-1399)。

由于偏移字段以8字节块编码,这意味着除了最后一个分片,每个分片的长度必须是8字节的倍数。

源IP地址和标识符字段的组合,使得接收端点能够将这三个分片正确地归类到一起。然后,根据偏移字段,它就能按正确顺序重组出原始的IP数据报。

分片的优缺点与避免策略

IP分片非常有用,因为它意味着发送端可以生成IP数据包,而无需担心路径上中间链路的最大传输单元是多少。这对于端点来说是一种很好的方式,尤其是在路径动态变化的情况下,它不需要了解整个路径的属性。

然而,在实际中,系统会尽量避免IP分片。原因在于,你将一个数据包变成了多个数据包,那么其中任何一个分片丢失的概率都会增加。假设网络有1%的丢包率,现在有三个分片,那么整个原始数据包因一个分片丢失而失效的概率就大大增加了。IP协议本身不支持对这些分片的可靠性保证或重传。如果一个分片丢失,通常需要由更高层协议(如TCP)来重传整个原始数据块的所有分片。

因此,通常我们希望避免IP分片。TCP协议有时采用一个有趣的技巧:主动选择一个合适的段大小来避免分片。由于TCP段的大小可以由TCP自己决定,它会尝试生成能够放入IP数据包中,并且在到达目的地的路径上不会触发分片的段。

实现这一点的方法之一是设置IP头部的“不分片”位。例如,TCP连接建立时,可以尝试发送一个标准的1500字节以太网帧大小的数据包,并设置“不分片”位。如果它收到一个ICMP错误消息,提示“需要分片但设置了不分片位,无法转发”,那么TCP就知道路径上存在更小的MTU,于是它会尝试更小的段大小。

有多种方法可以探测路径的MTU:

  • 进行二分查找(可能开销较大)。
  • 尝试一些常见的大小(如1500字节、576字节等)。
  • 遵循相关RFC中的建议。有一种方法是,TCP可以感知连接路径的属性,并据此选择一个最优的段大小。这个大小既要避免分片,又要能最小化头部开销,即在给定头部开销的情况下,最大化每个段的有效载荷,从而减少需要发送的段的总数量。

总结

本节课中,我们一起学习了网络中的分片与重组机制。我们了解到,当数据包大小超过链路MTU时,需要将其拆分为更小的分片进行传输,并在目的地重组。这个过程可以发生在链路层、网络层和传输层。我们重点剖析了IP协议的分片过程,包括标识符、偏移量和更多分片位等关键字段的作用。最后,我们探讨了IP分片的优缺点,并介绍了TCP如何通过路径MTU发现来主动避免分片,以提高传输效率和可靠性。理解分片与重组,对于掌握网络数据传输的基本原理至关重要。

📡 课程 P107:前向纠错(FEC)技术详解

在本节课中,我们将学习一种名为前向纠错的技术。这项技术允许网络在物理层发生比特错误时,依然能够成功接收数据帧。我们将探讨其基本原理、核心的编码思想,并通过一个具体的编码算法——里德-所罗门码来深入理解。最后,我们还会介绍一种名为交织的技术,它能进一步提升系统对长突发错误的抵抗能力。


🔍 噪声、误码率与信道容量

上一节我们提到了物理层的噪声和干扰会导致比特错误。本节中,我们来看看误码率与信道容量之间的理论关系。

如果对噪声做出一些数学假设(通常是高斯分布),那么信噪比与其比特误码率之间存在精确的关系。对于给定的信噪比,具体的比特误码率取决于所使用的调制方式。例如,在相同信噪比下,相移键控的比特误码率低于幅移键控。

提高信噪比(增强信号或降低噪声)可以降低比特误码率,但一个非常重要的事实是:比特误码率永远不会降为零。这是因为噪声遵循高斯分布,超过任何阈值的噪声概率总是非零的。因此,无论信号多强,总会丢失数据包。

从理论上看,如果以原始比特流发送数据包,效率会非常低。当信号强度高到误码率极低时,系统实际上远未达到香农极限。这就好比为了确保对方听清每个字,你必须说得非常慢、非常大声,这浪费了大量的信道容量。

例如,假设我们要传输一个1500字节(12000比特)的数据包,要求丢包率低于万分之一(10⁻⁴)。这意味着所有12000个比特都必须正确,因此需要满足以下条件:

(1 - 比特误码率)^12000 > 0.9999

计算可得,所需的比特误码率必须约为10⁻⁸。为了达到这个误码率,系统需要以高功率发射。如果计算在此功率下的理论信道容量(即完美利用信道时可达到的速度),会发现它比我们以极低丢包率发送12000比特数据包时的实际速度高出5倍。这意味着,如果仅仅通过提高功率来减少误码,你将浪费掉80%的信道容量

像LTE这样的高度工程化的无线系统,其运行效率非常接*理论最大值。那么,系统是如何做到不浪费那80%容量的呢?答案就是使用编码前向纠错技术。


💡 前向纠错与编码的基本思想

上一节我们看到了单纯提高功率的效率瓶颈。本节中,我们来看看如何通过编码和前向纠错来更高效地利用信道。

编码的基本思想非常简单:与其只发送原始比特并希望它们不被破坏,不如发送数据加上一点冗余。像CRC、MAC和校验和这样的机制只能检测错误,而编码则能让我们不仅检测,还能纠正错误。

核心思想是:添加少量冗余就可以纠正少量比特错误。发送只有少量错误的数据包,可以让你以更高的速率发送数据,而提高的速率足以弥补所增加的冗余开销。

所添加的冗余量由编码增益来描述。增益表示为一个分数,显示了链路层发送的比特数与物理层相应比特数之间的比率。

  • 编码增益 = 1/2:表示系统将数据包长度加倍,即每1比特链路层数据发送1比特冗余数据(总共2比特)。
  • 编码增益 = 3/4:表示每3比特链路层数据在物理层被发送为4比特。

增益为1意味着你只是在发送原始比特。这种主动添加冗余数据以纠正错误的方法,就叫做前向纠错。之所以称为“前向”,是因为发送方不需要接收方的任何反馈(不需要反向信道),而是利用前向信道的一部分容量来纠正错误。


🧮 里德-所罗门码原理

编码算法有很多种,这是一个有70多年历史的丰富研究领域。接下来,我们将介绍其中一种:里德-所罗门码。它有三个突出优点:

  1. 非常有效,应用广泛(如CD、DVD、DSL、WiMAX和RAID 6存储系统)。
  2. 非常灵活,既用于存储系统,也用于通信系统。
  3. 数学原理相对简单,易于解释和理解。

里德-所罗门码对数据块进行操作。例如,取一个223字节的数据块,添加32字节的冗余,将其变成一个255字节的块。

其基本直觉是:将你的数据块分成K个“块”(例如,每个“块”是一个字节)。将这K个值视为一个K-1次多项式的系数。例如,一个223字节的块对应一个222次多项式。

唯一性定理指出:任何n次多项式都由n+1个不同的数据点唯一确定。因此,如果我们有一个222次多项式,那么只要我们拥有该多项式上的223个正确的数据点,并且知道哪些点是正确的,我们就可以恢复出多项式的系数,也就是我们想发送的原始数据。

所以,实际操作中,发送方不是发送原始数据(多项式的系数),而是发送多项式上的一些点,例如 F(0), F(1), F(2)...。接收方收到这些数据点后,再从中计算出系数。

这里有一个数学上的复杂性:如果多项式系数很大,数据点的值可能会迅速超过一个“块”能容纳的大小。因此,这些点是在一个有限域上计算的。例如,由于每个“块”是一个字节,我们就在0到255的8位域上进行计算,溢出时会自动回绕。


⚠️ 错误类型与纠错能力

上一节我们假设接收方知道哪些数据点是正确的。但在实际通信中,接收方如何知道呢?里德-所罗门码区分两种错误:

  1. 擦除:接收方知道是错误的那些值(例如,数据块丢失,像RAID中硬盘故障)。
  2. 错误:接收方不知道是错误的那些值(通信系统中更常见的情况,某些块发生了比特错误但未被识别)。

里德-所罗门码能从多少擦除或错误中恢复,取决于冗余量。假设原始块数为K,编码后发送N个块,即增加了N-K个冗余块。

  • 对于擦除,接收方只需要K个正确的块即可恢复。因此,它可以恢复最多 N-K 个擦除。
  • 对于错误,接收方可以恢复最多 (N-K)/2 个错误。

接收方能处理的错误数量只有擦除的一半,因为它还需要找出哪些块是错误的。可以这样理解:接收方需要求解两组未知数——哪些接收块是坏的,以及多项式的系数。如果是擦除,接收方已经知道哪些块是坏的,所以不需要求解那部分未知数;但如果是错误,接收方就需要求解额外的未知数,因此需要更多正确的冗余字节来完成。

回到我们的例子:223字节数据块,编码为255字节(32字节冗余)。如果编码后的块中,有16个或更少的块发生比特错误,接收方就能成功解码并恢复原始的223字节数据。这个特定的码被称为(255, 223)码。


📊 编码实例分析

让我们通过一个例子来具体理解。在这个例子中,我们将编码6字节的数据“hello”,使用一个(7, 5)码。这意味着5个数据块被转换为7个编码块。

因为每个块有7个码字,所以每个块必须至少有3比特长(ceil(log₂(7)) = 3)。因此,对于(7, 5)码,我们取5个3比特的数据字,并将它们编码为7个3比特的码字。15比特变成了21比特

输入数据是48比特长(“hello”)。我们需要将其拆分为15比特的块,并发送整数个块。因此,我们必须将数据大小增加到60比特(4个块)。典型的解决方案是用零填充最后一个块。在这个例子中,我们用12个零比特填充最后一个块。

这60个数据比特被编码为4个21比特的码字,总共84比特。发送方发送这84比特,接收方运行里德-所罗门解码器得到60个数据比特,并恢复字符串“hello”。


💥 突发错误与交织技术

我们通常从“能恢复多长的连续错误突发”这个角度来思考编码方案。对于(7, 5)码:

  • 导致解码失败的最短错误突发是2比特(如果这两个错误恰好落在同一个块内两个相邻的码字中)。
  • 能够恢复的最长错误突发是6比特(前3比特破坏一个块中的一个码字,后3比特破坏下一个块中的一个码字)。

这些数字很小,部分原因是这个例子使用的码冗余很少且码字很小。想象一下,如果系统使用(255, 223)码和8比特码字,它能恢复的最长突发错误可以达到256比特。

有一种技术可以使里德-所罗门码对突发错误更具抵抗力,那就是交织。交织的基本思想是:不按线性顺序排列码字,而是将码字分散开,使得一个错误突发会破坏许多个块中的少量码字,而不是少数几个块中的大量码字

以下是两种交织方式:

  1. 码字交织:依次发送每个块的第1个码字,然后是每个块的第2个码字,以此类推。
  2. 比特交织:依次发送每个块的第1个比特,然后是每个块的第2个比特,以此类推。

关键点在于:对于里德-所罗门码,一个码字内无论有多少比特出错,整个码字都被视为无效。因此,面对突发错误时,我们希望:

  • 将错误分散到尽可能多的块中(这样每个块的错误就很少)。
  • 将错误集中在单个码字内(因为破坏一个码字的所有比特和只破坏一个比特,后果是一样的)。

码字交织使得一个码字的所有比特相邻,因此一个破坏单比特的错误突发通常会破坏该码字的所有比特。比特交织则将一个码字的比特分散开,因此很容易出现只破坏一个码字中单个比特的情况。因此,码字交织在抵抗导致解码失败的最短错误突发方面表现更好(需要更长的突发才能破坏同一个块的两个码字),而两者在抵抗最长可恢复错误突发方面的能力是相*的。


📝 课程总结

在本节课中,我们一起学习了:

  1. 问题的根源:物理层的噪声导致比特误码率永不为零,单纯提高发射功率会浪费大量信道容量。
  2. 解决方案的核心前向纠错技术,通过主动添加冗余数据,使接收方能够纠正一定数量的错误,无需重传。
  3. 关键的编码思想:以里德-所罗门码为例,通过将数据视为多项式系数,并发送多项式上的点来实现纠错。其纠错能力取决于冗余量,能纠正最多(N-K)/2个未知错误。
  4. 提升鲁棒性的技术交织,通过重新排列发送顺序,将长突发错误分散到多个数据块中,从而显著提高系统对这类错误的抵抗能力。

通过结合FEC和交织,现代通信系统能够在存在噪声的信道上高效、可靠地传输数据,使其性能接*理论极限。

计算机网络课程 P108:下层协议回顾 🌐

在本节课中,我们将回顾网络体系结构中的下层协议,特别是链路层。我们将探讨以太网的工作原理、无线网络的特点、信道容量以及错误处理机制。通过本次回顾,你将巩固对网络底层关键概念的理解。


互联网的“窄腰”:IP协议

到目前为止,本季度课程中已多次提及,IP协议是互联网的“窄腰”。

若想使用互联网,我们必须使用互联网协议(IP),这是唯一选择。然而,在链路层我们却拥有众多选择。IP协议可以运行在许多不同的链路层之上,例如以太网、Wi-Fi、DSL、3G蜂窝网络等。在不可靠的IP层之上,我们可以在多种不同的传输层协议中进行选择。

在本单元中,你学习了不同的链路层。你了解了链路层的服务模型、以太网的工作原理及其不同的运行速率。你观看了几个关于无线网络的视频,理解了无线网络的不同之处,以及为何需要介质访问控制协议来共享空中信道。你还学习了信道容量,它如何帮助我们确定通信信道的最大数据速率或容量,并且学习了错误检测与纠正机制。


有线网络之王:以太网

我们首先探讨了最常用的有线网络——以太网。如果你曾将电脑物理连接到网络,那几乎肯定是连接到一个以太网。尽管在20世纪90年代提出了许多不同的有线网络标准,其中一些被标准化、制造和销售,但以太网最终胜出,如今几乎普遍用于有线网络。

这是因为以太网非常简单、廉价且可靠。在一个交换式以太网中,当你有数据要发送时,可以直接发送。网络会学习地址,因此无需担心复杂的路由协议。以太网运行在几乎每栋办公楼都已安装的线缆上,这使得安装非常容易。

如今,几乎所有的以太网都使用以太网交换机,允许在同一网络中进行多个同时通信,并且每个链路都是全双工的,允许数据同时双向流动。在未来几年,我们将开始看到每秒40吉比特、100吉比特甚至更高速率的以太网。以太网看起来注定在未来多年内仍将主导有线链路层。

所有链路层都有其能承载的最大数据包大小。对于以太网,默认是1500字节。其他链路层可以承载更大的数据包,例如20世纪90年代的FDDI标准,其数据包长度可达4500字节。一些以太网被配置为承载所谓的巨型帧,长度可达9千字节。

我们将链路能承载的最长数据包称为其MTU或最大传输单元。当路由器连接两个具有不同MTU的链路时,它可能需要将IP数据报从MTU较大的链路传向MTU较小的链路时进行分片。

你学习了路由器如何使用IPv4首部中的分片字段来实现这一点,将IP数据报分解为新的、自包含的IP数据报。

网络不会重组这些分片。目的主机使用IPv4首部中的信息,在将数据交给TCP、UDP或ICMP之前,将数据按正确顺序重新组合。

IP分片现在不如过去常见,原因有二。首先,今天大多数有线网络都使用以太网,因此大多数链路的MTU往往是1500字节,无需分片。其次,主机在建立TCP连接时经常使用MTU发现机制,以确定路径上的最小MTU。发送方不会发送大于该MTU的数据包,从而消除了沿途分片的需要。当我们讨论传输协议的MSS或最大段大小时,它使用的就是这种MTU发现协议。


无线网络的独特挑战

无线网络与有线网络截然不同。在有线网络中,链路具有恒定的数据速率,但在无线网络中,链路速度总是在变化。

这有几个原因:来自附*无线网络和其他在同频段运行的设备(如微波炉和无绳电话)的干扰;也可能是由于信道的衰落,如阴影效应和多径效应。

无线网络还遭受所谓的隐藏终端问题。当两个客户端无法直接相互通信,但都能与一个接入点通信时,就会发生这种情况。因为它们听不到对方,所以不知道如何避免同时传输,从而需要在网络中进行额外的协调。

无线网络不同的另一个方面是,信道天然地广播所有通信。这意味着发送方需要轮流传输,这导致了介质访问控制协议的产生,例如Wi-Fi中使用的CSMA协议。共享的广播信道也意味着我们需要更加小心地保护数据。与有线网络相比,邻居中的任何人都能更容易地窃听我们的通信。

你还学习了一些支配我们如何构建物理链路的基本通信原理。

你了解了比特错误,以及它们如何导致我们在线上错误地解码数据包;你学习了编码数据的方法,以便在错误发生时更容易检测;你还了解了纠错码的工作原理以及我们何时使用它们。

一般来说,我们在比特错误频繁或重传损坏数据包成本很高的环境中使用纠错码。例如,在一个具有非常大带宽延迟积的网络中。


通信的理论基石:香农容量

最后,但或许也是最重要的,你学习了香农容量。克劳德·香农创立了极其强大的信息论领域,其工作的核心是推导出一个信道能够进行无差错通信的最大速率,现在我们称之为香农容量。

香农容量的显著特性在于,它为我们提供了一个根本性的、无法逃避的限制,即信息在信道上能够承载的最大速率,无论我们发明多么巧妙的编码方案。

我们描述的所有通信原理,让你初步领略了在电气工程课程中关于通信理论或信息论将会学习到的一些内容。如果你真的喜欢这些材料,将来可以考虑选修相关的电气工程课程。


在本节课中,我们一起回顾了网络下层协议的核心内容。我们探讨了以太网的统治地位及其简单可靠的设计,分析了无线网络面临的独特挑战如隐藏终端问题和变化的链路质量,并学习了信道容量和错误处理的基本原理。这些知识构成了理解现代计算机网络如何工作的坚实基础。

课程 P109:网络安全基础 🛡️

在本节课中,我们将要学习网络安全的基础知识。通常,我们在新闻中读到关于互联网和网络的报道,往往是因为某些安全漏洞被利用或发现。这些漏洞可能存在于软件中,有时也存在于网络基础设施本身。这些安全问题之所以暴露,通常是因为个人、公司或国家为了窃取或篡改他人数据而发起的攻击。

常见的网络攻击类型 🔓

上一节我们介绍了网络安全的重要性,本节中我们来看看几种常见的网络攻击方式。攻击网络的方法有很多,我们将介绍一系列以不同方式运作的攻击手段。

以下是几种主要的攻击类型:

  • 窃听:这是最常见的一种。攻击者可以简单地窃听、交换或监听他人的通信。在某些网络中,这出人意料地容易实现。攻击者可以窃听像无线网络这样的广播网络,或者迫使网络以某种方式暴露或广播信息,从而更容易被截获。
  • 伪装:攻击者伪装成网络基础设施的一部分,向发送方主机提供虚假信息。例如,可以伪造来自DHCP服务器或DNS服务器的响应,诱使客户端将数据发送到非预期的目的地。这可能导致数据被重定向到攻击者处(即“中间人攻击”),或者使发送方无法与网络的特定部分通信,从而实现审查或阻断。
  • 劫持:有时,攻击者能够完全劫持一个终端主机并伪装成它,从而彻底终止原有的通信。例如,在用户进行电子商务交易时窃取其信用卡信息。
  • 拒绝服务:这种攻击旨在通过压垮发送方或关键基础设施,使其无法再进行任何通信,从而完全阻止某人进行通信。

网络安全三原则 🔐

互联网环境充满危险。尽管互联网本身可能不安全,但我们可以运用以下三个原则来保护自己的网络。

  1. 保密性:其核心思想是,即使他人能看到我们的通信内容,我们也希望进行安全的、对他人隐藏的通信。如果实现了保密性,你就可以与另一方通信,而旁观者虽然能看到通信发生,却无法知晓具体内容。
  2. 完整性:保密性确保了他人不知道我们在说什么,但他们仍可能篡改通信内容。完整性则能确保我们的通信在传输过程中未被篡改,接收到的信息就是发送方原本想传达的信息。
  3. 真实性:我能确信正在与我通信的另一方,确实是他们所声称的身份吗?事实证明,有一些方法可以实现这一点。

密码学:安全通信的基础 🔑

上一节我们了解了安全通信的目标,本节中我们来看看实现这些目标的基础技术。用于实现保密性、完整性和真实性的基本技术都依赖于密码学,即运用数学工具和密码来实现秘密通信。

其核心思想是,如果我们使用正确的密码学工具,即使在像互联网这样不安全的网络上,也能实现安全通信。

以下是当今互联网中使用的一些基本密码学工具:

  • 密码散列函数:例如 SHA-256
  • 认证码:例如 HMAC
  • 对称加密:例如 AES 算法。
  • 公钥密码学:例如 RSA 算法。
  • 证书与数字签名:用于验证身份和信息的真实性。

总结 📝

本节课中我们一起学习了网络安全的基础。我们首先了解了常见的网络攻击类型,如窃听、伪装、劫持和拒绝服务攻击。接着,我们探讨了保障网络安全的三个核心原则:保密性、完整性和真实性。最后,我们认识到,密码学是实现这些安全目标的数学基础,并简要介绍了几种关键的密码学工具。通过本单元的学习,你应该对如何着手保护自己的网络有了初步的认识。

课程 P11:字节序详解 🧠

在本节课中,我们将学习计算机系统中一个重要的底层概念——字节序。字节序决定了多字节数据在内存中的存储顺序,理解它对于处理网络通信、文件解析和跨*台数据交换至关重要。


概述

字节序主要分为两种:大端序小端序。我们将通过具体的数字示例,学习如何判断给定数据的字节序,并理解其背后的原理。


什么是字节序?

字节序描述了多字节数据(如整数、浮点数)的各个字节在内存中存放的顺序。

  • 大端序:最高有效字节存储在最低的内存地址。
  • 小端序:最低有效字节存储在最低的内存地址。

“最高有效字节”可以理解为数字中权重最大的部分,例如在十进制数 1234 中,“1”(代表一千)就是最高有效数字。


示例分析:数字 53

上一节我们介绍了字节序的基本概念,本节中我们通过数字 53 的存储来具体分析。

数字 53 在十六进制中表示为 0x35。假设它被存储在两个连续的字节中。

以下是其两种可能的存储方式:

  • 小端序存储:最低有效字节 0x35 存放在第一个(低地址)字节。

    地址增长方向 →
    +----+----+
    |0x35|0x00|
    +----+----+
    (低地址) (高地址)
    

    读取时,从低地址到高地址得到 0x35 0x00,解释为数字 0x0035,即十进制的 53

  • 大端序存储:最高有效字节 0x00 存放在第一个(低地址)字节。

    地址增长方向 →
    +----+----+
    |0x00|0x35|
    +----+----+
    (低地址) (高地址)
    

    读取时,从低地址到高地址得到 0x00 0x35,解释为数字 0x0035,同样是十进制的 53

结论:对于数字 53,其存储序列 0x35, 0x00 对应的是小端序


示例分析:数字 4116

现在,我们来看一个更大的数字 4116,进一步巩固判断方法。

数字 4116 等于 4096 + 20。在十六进制中:

  • 4096 = 0x1000
  • 20 = 0x0014
  • 因此 4116 = 0x1014

以下是其存储分析:

  • 如果存储序列是 0x10, 0x14,这意味着权重更大的字节 0x10(代表 4096)存放在更低的地址。这符合大端序的定义。
  • 如果存储序列是 0x14, 0x10,则是小端序

根据给定的上下文,4116 的存储被判定为大端序,即序列为 0x10, 0x14


快速判断技巧:奇偶性

面对更复杂的数字时,我们无需计算完整的十六进制表示。一个快速的判断技巧是利用数字的奇偶性

原理如下:

  • 一个数字是奇数还是偶数,仅由它的最低有效位(即最后一个字节的最低位)决定。
  • 在小端序中,第一个字节(最低地址)就是最低有效字节。
  • 在大端序中,最后一个字节(最高地址)才是最低有效字节。

因此,我们可以通过检查给定字节序列的第一个字节来判断:

以下是判断步骤:

  1. 查看给定字节序列的第一个字节(低地址字节)。
  2. 如果这个字节表示的数是奇数,那么它很可能就是最低有效字节,存储方式为小端序
  3. 如果这个字节表示的数是偶数,那么它很可能不是最低有效字节(最低有效字节在别处),存储方式可能为大端序

应用示例
假设一个数字的存储序列以 0x21 开头。0x21 是十进制 33,为奇数。这表明 0x21 就是决定奇偶性的最低有效字节,因此存储方式是小端序
反之,如果序列以 0x10 开头(十进制 16,偶数),则存储方式可能是大端序


总结

本节课中我们一起学习了字节序的核心知识:

  1. 字节序分为大端序(高位在前)和小端序(低位在前)。
  2. 可以通过分析具体数字(如 53, 4116)的十六进制存储序列来判断其字节序。
  3. 掌握了一个快速判断技巧:观察序列第一个字节的奇偶性,奇数常对应小端序,偶数常对应大端序。

理解字节序是掌握计算机数据存储和网络传输的基础,希望本教程能帮助你建立清晰的概念。

课程 P110:网络安全入门 🔐

在本节课中,我们将要学习网络安全的基本概念。我们会探讨网络可能遭受攻击的几种方式,并明确一个安全的网络应具备哪些核心特性。


当我们在报纸上读到关于计算机网络的新闻时,通常是因为它们遭到了攻击或已被攻破。几乎每周我们都能读到黑客入侵并窃取数百万信用卡号和其他私人数据的报道。这可能是通过钓鱼攻击,或是利用其他漏洞来访问一个本应是私有的网络。

或者,我们可能会读到一种旨在控制计算机、将其变成僵尸网络大军的新型蠕虫病毒,例如21世纪初臭名昭著的“红色代码”和“震荡波”蠕虫。僵尸网络是由主控者控制的一批受感染计算机,通常被用来发送垃圾邮件。虽然垃圾邮件的数量似乎略有下降,但报告表明,每天发送的所有电子邮件中,有75%到95%是垃圾邮件,总计每天达数亿封。

蠕虫病毒也被一国政府用于攻击另一国政府。例如,2010年的“震网”蠕虫被广泛认为是由美国和以色列政府制造的,用于攻击伊朗处理核材料的离心机。

在本视频中,我们将探讨攻击者可能危害网络的几种方式,并解释我们希望网络具备的安全特性。


通信被危害的几种方式

上一节我们介绍了网络安全问题的普遍性,本节中我们来看看攻击者具体如何危害通信。首先,让我们探索通信可能被危害的不同方式。

第一种也是最简单的方式,是攻击者窃听他人的私人通信。这意味着被动地嗅探和记录网络数据,或者监听元数据,例如记录连接已建立的事实,而不一定记录连接内的数据内容。连接元数据最*因美国国家安全局承认记录通话和连接信息(据称不记录内容)而声名狼藉。

以下是窃听网络的几种方法:

  • 物理层窃听:攻击者可以被动地搭接电缆或光缆。
  • 无线监听:如果使用Wi-Fi,攻击者可以监听广播的无线数据包。
  • 路由器复制:攻击者可以说服路由器复制并转发数据包副本。

在每种情况下,攻击者都可以使用像Wireshark这样的标准工具来解码协议并理解用户数据。

第二种危害类型是攻击者在数据通过网络时修改、删除或插入数据。换句话说,他们主动篡改我们的数据,改变数据包内容,在我们不知情的情况下将数据包重定向到不同的恶意服务器,或者控制我们的终端主机。这可能通过说服我们下载基于钓鱼攻击的恶意软件,或利用我们计算机或通信方式中的漏洞来实现。例如,稍后我们将看到如何在不被任何一端察觉的情况下劫持一个正在进行的TCP连接。

最后,攻击者可能只是想阻止通信双方进行通信。这类攻击通常被称为拒绝服务攻击。有时,这些攻击是通过从遍布互联网的不同僵尸网络生成数十亿条消息,来淹没服务器或整个网络来实施的。我们将在后面的视频中了解更多关于拒绝服务攻击的内容。


窃听攻击实例分析

上一节我们了解了攻击的几种类型,本节我们通过一个具体例子来深入理解窃听攻击。让我们看一个窃听的例子。想象一下,爱丽丝正在从一个电子商务网站进行在线购物。她使用笔记本电脑连接到本地的Wi-Fi接入点,然后通过互联网连接到Amazon.com。她浏览网站并使用普通的HTTP协议进行信用卡购买。

不幸的是,她不知道的是,攻击者正在监听她的操作。攻击者可以通过几种方式进行窃听:

  • 监听无线数据包:任何拥有笔记本电脑和嗅探工具的人都可以监听空气中的数据包,如果数据未加密,他们就能看到内容。
  • 搭接物理线路:攻击者可以通过放置被动探测器来拾取电缆泄漏的微小电磁信号,或者直接在电缆下方插入电气连接。
  • 窃听骨干网:如果攻击者窃听互联网骨干网中的长途链路,他们更可能搭接光纤。这可以通过放置一种叫做光耦合器的设备来实现,该设备将一小部分光信号分流到另一根光纤上,然后进行监听和解码。
  • 劫持网络设备:没有物理访问权限的攻击者可能会设法颠覆路径上的交换机和路由器,诱使其中一台设备复制数据并将其转发到攻击者的计算机。这可以通过远程颠覆以太网、IP或DNS流量来实现。或者,攻击者可能设法侵入路由器控制台并完全接管路由器。

在我们的例子中,如果攻击者成功窃听了明文的HTTP通信,他或她就可以获取爱丽丝的私人数据,如信用卡号和家庭地址。在后面的视频中,我们将学习HTTPS如何在实际中防止这种情况发生。


中间人攻击与流量重定向

如果攻击者能够将自己插入到爱丽丝和Amazon.com之间的通信中间,那么攻击者就可以在中间终止HTTP连接,对爱丽丝假装是亚马逊,对亚马逊假装是爱丽丝。攻击者可以简单地传递数据并记录而不更改它,或者攻击者可以更改数据,例如修改送货地址,导致购买的商品被送到攻击者那里而不是爱丽丝那里。这些所谓的中间人攻击很难被检测到,因为双方都可能认为自己在与合法的终端主机通信。

第三种攻击方式是,在不被爱丽丝察觉的情况下,将流量从服务器重定向出去。如果攻击者能够欺骗路由器,将目的地为Amazon.com的数据包转发给攻击者,那么攻击者就可以响应并假装是亚马逊。或者,攻击者可能欺骗爱丽丝的DNS服务器,当爱丽丝试图查找亚马逊的IP地址时,返回攻击者的IP地址。在每种情况下,爱丽丝都可能被迫浏览攻击者的网站,并被诱使在那里输入她的信用卡信息。


安全通信的核心特性

显然,爱丽丝不会高兴,她希望自己的通信更加安全。一般来说,当我们说希望互联网上的通信安全时,我们指的是希望具备以下特性:

  1. 保密性:我们不希望任何人监听我们的通信。为此,我们使用加密。我们将在接下来的一个视频中描述其工作原理。
  2. 完整性:我们不希望我们的消息在传输过程中被篡改。证明消息未被篡改的最常见方法是附加一个消息认证码。MAC基于加密技术,并结合对传输消息计算哈希值。我们将在后续视频中学习消息认证码。
  3. 认证:我们通常希望确认与我们通信的另一方的身份。在我们的例子中,爱丽丝希望在输入信用卡详细信息之前,确认她确实在与她信任的亚马逊通信。在后面的视频中,我们将学习数字签名证书,它们帮助我们确保我们确实在与我们认为的对象通信。
  4. 可用性:我们不希望有人一开始就阻止我们进行通信。你可能听说过拒绝服务攻击,即攻击者淹没网络或一组服务器,使其无法正常工作。我们很快将研究拒绝服务攻击。

总结与预告

本节课中,我们一起学习了网络安全的基本概念。我们探讨了网络可能遭受的几种主要攻击类型:窃听、数据篡改和拒绝服务攻击。我们还通过爱丽丝在线购物的例子,具体分析了窃听、中间人攻击和流量重定向是如何发生的。最后,我们明确了安全通信应具备的四个核心特性:保密性、完整性、认证和可用性。

在接下来的几个视频中,我们将深入研究不同类型的攻击。我们将学习窃听、重定向以太网/IP/DNS流量、劫持正在运行的TCP连接以及拒绝服务攻击。

课程 P111:二层网络攻击详解 🔓

在本节课中,我们将学习几种通过入侵本地网络(通常运行在第二层)来实施的常见攻击方式。我们将探讨攻击者如何迫使网络广播数据包,以及如何通过伪装成关键网络服务器来劫持流量。


网络窃听与混杂模式

上一节我们介绍了二层网络攻击的基本概念。本节中,我们来看看攻击者进行网络窃听的一种基础方法。

如果我们将网络接口设置为混杂模式,窃听就变得相当容易。在此模式下,网络接口会捕获所有流经的数据包,而不仅仅是那些目标地址是自身以太网地址的数据包。

计算机允许这种操作模式,是为了能够充当以太网交换机。例如,Linux操作系统就内置了以太网交换代码。当Wireshark运行时,它首先会将你的接口置于混杂模式,以便能看到所有数据包。

在Wi-Fi网络和早期的以太网中,数据包被广播到单一的共享链路上,这种窃听方式尤其容易。但在使用以太网交换机的现代网络中,数据包通常只在源和目的地之间的链路上传输,因此这种方法效果不佳。


通过MAC泛洪攻击强制广播

既然现代交换网络限制了广播,那么攻击者如何实施窃听呢?本节将介绍一种通过攻击交换机转发表来强制网络广播所有数据包的方法。

正如我们在第7单元所见,以太网多年来已经发生了变化。如今的以太网使用交换机,而非单一的共享电缆。使用交换机是因为它允许网络中同时进行多次通信,这对性能是好事,但对攻击者却是坏消息,因为数据包只流经Alice和Bob之间的两条链路,攻击者无法看到。

一种常见的攻击方式是攻击以太网交换机中的转发表。回想一下,以太网交换机通过观察网络中的数据包来学习终端主机的地址。例如,图中Alice和Bob之间的交换机,会在他们发送数据包时学习其以太网地址。

以下是一个交换机学习到一些地址后,其转发表可能的样子:

端口1: 地址 AA:BB:CC:DD:EE:01 (Alice)
端口2: 地址 AA:BB:CC:DD:EE:02 (Bob)

实际上,这些表比这大得多,通常有数万或数十万个条目,但这里为了简化只展示几个。请记住,如果交换机收到一个以太网目的地址不在其转发表中的数据包,它就会广播该数据包。

那么,攻击者如何说服交换机广播所有数据包呢?它可以通过不断用其他地址填满转发表来实现。以下是攻击者可以采取的步骤:

  1. 发送大量伪造数据包:攻击者持续高速发送带有新以太网地址的数据包。
  2. 交换机学习并替换:交换机会学习这些地址,并替换表中已有的条目。通常,替换策略是“最*最少使用”。
  3. 目标条目被驱逐:如果攻击者发送的速率足够高,表中关于Alice和Bob的条目就会被不断驱逐出去。
  4. 数据包被广播:一旦Alice和Bob的地址不在表中,发往他们的所有数据包都会被广播,从而被攻击者看到。

这种攻击被称为 MAC泛洪攻击


伪装服务器攻击:DHCP与ARP

除了泛洪攻击,攻击者还有更“精准”的方法。本节我们将探讨攻击者如何通过伪装成DHCP或ARP服务器来重定向流量。

另一种常见的攻击类型是设置伪DHCP服务器。在此攻击中,攻击者试图说服你使用其伪DHCP服务器,而非合法的服务器。

回忆一下,DHCP是网络提供的一项服务,用于在计算机启动或首次接入网络时帮助其进行配置。你的计算机会发送一系列广播发现数据包来寻找DHCP服务器(通常托管在最*的路由器上)。找到后,计算机会发送请求,要求分配本地网络上的IP地址、默认路由器地址以及应使用的DNS服务器地址。

如果伪DHCP服务器能比合法服务器响应更快,它就可以首先响应Alice,并给出它想要的任何配置信息。攻击者可以通过以下几种方式进行破坏:

  • 提供错误的路由器地址:让Alice将流量发送给攻击者,而非真正的路由器。这使攻击者能在Alice不知情的情况下轻松建立中间人攻击。
  • 提供伪DNS服务器地址:当Alice未来查询IP地址(例如下次访问Google.com时),伪DNS服务器可以返回另一个服务器的IP地址,从而截获Alice的流量。

最后,攻击者还可以设置伪ARP服务器。当Alice向本地主机或通过路由器发送数据包时,她会首先发送ARP请求以查找下一跳的以太网地址。她先发送一个广播ARP请求包,ARP服务器则回复她所寻找的合法以太网地址。

但如果攻击者设置了一个比合法ARP服务器响应更快的伪ARP服务器,攻击者就可以给Alice提供错误信息。如果攻击者回复的是本地网络中一个伪服务器的以太网地址,那么Alice的所有流量都将被发送到这个伪服务器。这是另一种在Alice不知情的情况下,通过将所有流量经由伪服务器转发来建立中间人攻击的简便方法。


总结 🎯

本节课中,我们一起学习了两种主要的二层网络攻击方式。首先,我们了解了MAC泛洪攻击,它通过填满交换机转发表来迫使网络广播数据包,从而实现窃听。其次,我们探讨了伪装服务器攻击,包括设置伪DHCP和伪ARP服务器,通过提供错误的网络配置信息,将用户流量重定向到攻击者控制的节点,从而实施中间人攻击。理解这些攻击原理是构建安全网络防御的重要基础。

课程 P112:MAC 泛洪攻击演示 🚨

在本节课中,我们将学习 MAC 泛洪攻击的原理,并通过一个在 MiniNet 仿真环境中运行的演示,直观地展示攻击者如何通过泛洪交换机转发表来窃听本应隔离的网络流量。

攻击原理概述

上一节我们介绍了交换机学习机制的基本原理。本节中我们来看看攻击者如何利用这种机制的局限性。MAC 泛洪攻击的核心是:攻击者向网络发送大量源 MAC 地址随机的以太网帧,迫使交换机的 MAC 地址表(转发表)被填满并溢出。当合法设备的 MAC 地址条目因溢出而被驱逐后,发往该设备的流量将被迫以广播方式发送,从而使攻击者能够窃听到这些流量。

演示环境与正常状态验证

首先,我们验证在正常情况下,攻击者无法窃听通信。演示运行在 MiniNet 仿真系统上,这意味着你可以在自己的计算机上安全、轻松地复现此演示。

演示由斯坦福大学的博士生 T-Wifi 创建。屏幕上有三个窗口,分别代表 Alice、Bob 和 Eve(攻击者)。在底部,Alice 正在向 Bob 发送 ping 数据包,而 Eve 在其机器上运行 tcpdump 工具,监听来自 Alice IP 地址 10.0.0.1 的流量。

正如你所见,tcpdump 没有捕获到任何流量,Eve 完全听不到任何信息。这表明交换机的学习机制工作正常,流量没有被广播。

攻击过程演示

接下来,Eve 发起攻击。以下是攻击的具体步骤:

  1. 发起泛洪:Eve 运行攻击脚本,向网络泛洪大量随机生成的源 MAC 地址的以太网帧。
  2. 表项溢出:交换机持续学习这些新地址,直到其转发表被填满并发生溢出,导致之前学到的 Alice 服务器的 MAC 地址条目被驱逐。
  3. 流量广播与窃听:此时,Alice 仍在向 Bob 发送 ping 包。由于交换机中已无 Alice 的准确转发表项,这些数据包被广播到所有端口。运行在 Eve 机器上的 tcpdump 现在可以看到这些数据包并在屏幕上报告出来。
  4. 持续对抗:Eve 并非能看到所有数据包,因为交换机偶尔会重新成功学习到 Alice 的地址。但由于 Eve 持续不断的以太网帧泛洪,Alice 的地址条目很快又会被再次驱逐。
  5. 攻击停止:当 Eve 停止生成新的以太网帧后,交换机将重新学习到 Alice 的以太网地址,并停止广播 Alice 和 Bob 之间的流量。这样,Eve 就无法再窃听到他们的通信。

如何自行复现

如果你有兴趣,可以自行复现这个演示。只需从屏幕底部显示的 URL 下载 MiniNet 脚本,然后在你自己计算机的 MiniNet 实例中运行它即可。

课程总结

本节课中,我们一起学习了 MAC 泛洪攻击的完整过程。我们了解到,攻击者通过泛洪伪造的 MAC 地址耗尽交换机转发表空间,从而迫使目标流量被广播,达到窃听的目的。这个演示清晰地揭示了依赖自主学习机制的交换网络所面临的安全风险。

课程 P113:DHCP 攻击演示 🧪

在本节课中,我们将学习 DHCP 攻击的基本原理。我们将通过一个演示,了解攻击者如何伪装成合法的 DHCP 服务器,从而错误地配置受害主机的网络设置,并引导其流量至恶意服务器。


演示环境概述

在演示中,三台主机连接到交换机 S1。主机 H1 是受害者 Alice 的机器,运行着正常的 DHCP 客户端。主机 DHCP 运行着正常的 DHCP 服务器,负责为 Alice 的机器配置网络,包括指向互联网上正常 DNS 服务器的信息。主机 Evil 由攻击者 Eve 控制,运行着恶意 DHCP 服务器恶意 DNS 服务器恶意 Web 服务器

首先,我们假设 Eve 尚未发起攻击。我们将看到正常的 DHCP 服务器如何正确配置 Alice 的机器,使其能够正常访问互联网。


正常网络访问流程

上一节我们介绍了演示环境,本节中我们来看看在未受攻击时,Alice 如何正常访问网络。

Alice 使用主机 H1 上的 Firefox 浏览器浏览网页。如下图所示,她可以成功访问斯坦福大学的网站。

她的计算机 H1 运行 DHCP 客户端,以获取 IP 地址、本地路由器地址和 DNS 服务器地址。如果我们使用 dig 命令查询另一个域名(如 Amazon.com),可以看到 DNS 服务器(本例中是 Google 运营的公共 DNS 服务器 8.8.8.8)正常响应查询,返回 Amazon 的 IP 地址,并且该网站在 Firefox 中能按预期加载。


攻击者发起攻击

了解了正常流程后,现在让我们看看攻击者 Eve 如何破坏这一流程。

攻击者 Eve 在 Evil 主机上启动了三个进程:一个恶意 DHCP 服务器、一个恶意 DNS 服务器和一个 Web 服务器。Eve 的目标是迫使 Alice 的所有 Web 访问都指向 Eve 自己的 Web 服务器。

DHCP 客户端需要定期续订其 IP 地址租约。在演示中我们可以看到,当 H1 发出 DHCP 发现请求时,位于 10.0.0.50 的正常 DHCP 服务器会响应一个包含合法 DNS 服务器地址 8.8.8.8 的提供报文。然而,Alice 的机器首先收到了来自恶意 DHCP 服务器的提供报文并接受了它。


攻击后果

现在,Alice 陷入了麻烦。她的机器开始使用 Eve 的恶意 DNS 服务器(地址为 10.0.0.66)。当 Alice 的浏览器请求 Google.com 的 IP 地址时,恶意 DNS 服务器会告诉 Alice 的机器使用 Eve 的 Web 服务器,于是发生了下图所示的情况。

当她再次访问 Amazon.com 时,由于 Firefox 缓存了之前的 DNS 结果,大部分正确的网站内容仍会出现。但一旦 Firefox 执行新的 DNS 查询(我们可以通过按 Shift+刷新 来强制触发),她就会被导向恶意 Web 服务器的 IP 地址。如果她访问一个新网站(如 Yahoo.com),同样会最终访问到恶意网站。

以下是攻击者 Eve 可能实施的一些恶意行为:

  • 拒绝服务: 直接拒绝或阻止 Alice 访问特定网站。
  • 网络钓鱼: 模仿 Alice 访问的网站(尤其是电子商务网站)的外观,诱骗 Alice 泄露信用卡或其他个人信息。
  • 流量监控: 充当透明代理,监视和记录 Alice 的所有网络流量。

恢复与防御启示

当关闭恶意 DHCP 客户端和 DNS 服务器后,Alice 最终会恢复使用正确的本地 DHCP 服务器。她首次重新访问同一网站时,浏览器可能仍缓存了错误的 DNS 记录,并尝试访问恶意 Web 服务器。但最终,Alice 的主机将开始使用正确的 DNS 服务器,她的网络将恢复正常工作。

这个视频展示了,如果你能访问本地网络流量,发起攻击是多么容易。如果你能拦截并抢先响应网络中的 DHCP 流量,你就可以安装自己的 DNS 服务器,进而将流量重定向到你自己的 Web 服务器或任何其他类型的服务器。这在能够访问本地网络的情况下非常容易实现。


如何自行运行演示

如果你想亲自运行这个演示,可以按照以下步骤操作:

  1. 下载演示脚本。脚本的 URL 已显示在屏幕上。
  2. 在你自己的 Mini-Net 仿真实例中运行该脚本。


课程总结

本节课中,我们一起学习了 DHCP 攻击的完整过程。我们看到了攻击者如何利用恶意 DHCP 服务器抢先响应,错误配置受害主机的 DNS 设置,从而将网络流量重定向到恶意服务器。这个演示强调了本地网络安全的重要性,以及 DHCP 服务若缺乏认证机制所面临的潜在风险。

课程 P114:SSH 中间人攻击演示 🕵️

在本节课中,我们将学习并演示一次 SSH 中间人攻击。我们将看到攻击者如何通过 ARP 欺骗技术,插入到 SSH 客户端与服务器之间,从而窃听通信内容。

攻击原理概述

上一节我们介绍了中间人攻击的基本概念,本节中我们来看看它在 SSH 场景下的具体实现。攻击的核心在于,恶意攻击者通过发送伪造的 ARP 消息,欺骗网络中的其他设备,使其误以为攻击者的 MAC 地址是通信目标的地址。

核心公式Alice -> (误以为) Eve(MAC) -> BobBob -> (误以为) Eve(MAC) -> Alice

这样,当 Alice 尝试连接 Bob 时,网络流量实际上会先经过攻击者 Eve。Eve 可以转发这些数据包以维持连接,同时在其中窃听和解密 SSH 数据。

正常网络环境验证

在发起攻击前,我们首先验证在正常网络条件下,攻击者无法窃听 Alice 与 Bob 之间的通信。

以下是验证步骤:

  1. Alice 持续向 Bob 发送 ping 请求。
  2. 攻击者 Eve 在其机器上运行 tcpdump,试图监听来自 Alice IP 地址(192.168.0.3)的流量。
  3. 结果显示,Eve 的 tcpdump 没有捕获到任何流量。
  4. 而在 Bob 的机器上运行 tcpdump,则可以正确看到来自 Alice 的数据包。

这证实了在未受干扰的网络中,通信是直接且私密的。

实施 ARP 欺骗攻击

接下来,Eve 将发起攻击。她通过发送伪造的 ARP 数据包,欺骗网络交换机,使其误认为 Alice 和 Bob 的 MAC 地址都是 Eve 的 MAC 地址。

我们使用一个名为 Ettercap 的工具来执行此攻击。Ettercap 不仅能方便地进行 ARP 欺骗,还能通过强制客户端和服务器使用较旧、安全性较低的 SSH 版本 1 来帮助解密 SSH 数据,并将解码后的数据保存在本地供我们查看。

启动 ARP 欺骗和网络嗅探的命令类似于:

ettercap -T -M arp:remote /192.168.0.1// /192.168.0.2//

启动 ARP 欺骗后,Eve 的 tcpdump 现在可以成功看到 Alice 发送给 Bob 的数据包,证明流量已被重定向。

窃听 SSH 连接

现在,让我们从 Alice 向 Bob 发起一个 SSH 连接。

攻击效果立即显现:

  1. Ettercap 捕获了该连接。
  2. 工具成功解码了 Alice 为身份验证提供的用户名和密码
  3. 在 Eve 的机器上,我们可以查看一个日志文件,其中记录了 Alice 与 Bob 之间所有解码后的 SSH 活动记录。

至此,我们成功地使用中间人攻击窃听了一次 SSH 连接。

如何复现此演示

如果你有兴趣,可以按照以下 GitHub 仓库中的详细说明,在自己的计算机上复现这个演示。

请注意:此演示仅在受控的实验室环境(如 Mininet 仿真系统)中进行,用于教育目的。未经授权对他人网络进行此类攻击是非法的。

课程总结

本节课中,我们一起学习了 SSH 中间人攻击的完整过程。我们了解了攻击者如何利用 ARP 欺骗 成为通信双方的“中间人”,并使用特定工具(如 Ettercap)来拦截和解密 SSH 流量。这个演示清晰地揭示了依赖未加密或弱加密协议,以及在不可信网络中进行通信所面临的风险。

课程P115:TCP连接劫持攻击详解 🕵️

在本节课中,我们将学习一种名为TCP连接劫持的网络攻击技术。这种攻击允许攻击者秘密地介入两个通信方之间已建立的TCP连接,并篡改传输的数据,而通信双方对此毫不知情。

概述

截至目前,你已经见识了多种攻击计算机的方法。我们可以强制网络广播数据包,或者将数据包重定向到恶意服务器。在本视频中,我们将看到另一个令人不安的例子。在这个场景中,Alice和Bob正在通过TCP连接愉快地通信,而攻击者Eve将介入这个TCP连接的中间,在连接建立后劫持它。她将操纵连接内部的数据,而双方都不会察觉。

这种攻击相当棘手,比之前的攻击更复杂。因为Eve必须弄清楚Alice和Bob之间TCP连接的当前状态,以便发送数据,并且这些数据必须落在正确的序列号范围内,同时不能破坏连接两端状态机的TCP状态。

攻击原理

正如我们在SSH中间人攻击中看到的那样,攻击者Eve将在局域网中广播伪造的ARP消息,导致Alice认为她应该使用Eve的MAC地址来联系Bob。同时,伪造的ARP数据包也使Bob认为他也应该使用Eve的MAC地址来联系Alice。

因此,Alice和Bob之间所有的TCP流量实际上都将通过Eve路由。Eve将简单地充当Alice和Bob之间的桥梁,来回传递TCP请求和响应。同时,Eve会寻找TCP数据段中的模式,等待劫持和操纵连接的机会。

让我们更详细地了解一下。

演示环境搭建

与其他演示一样,我将使用MiniNet仿真系统来演示这个例子。你可以轻松安全地在自己的计算机上运行此演示,稍后我会告诉你如何操作。这个例子是由Sean Choi创建的。

首先,让我们验证在正常情况下,Eve无法劫持和操纵Alice和Bob之间的TCP连接。

我们将使用的TCP应用类型是HTTP,这是一种我们现在都非常熟悉的应用层协议。Alice正在向Bob请求一个网页,Bob在他的计算机上运行一个简单的HTTP服务器,并将从其本地文件系统响应一个静态网页。

正如我们所见,Alice收到了一个正确的网页,没有任何恶意信息。

实施攻击

接下来,Eve发起攻击,她发送伪造的ARP数据包,导致Alice和Bob都认为他们应该使用Eve的MAC地址来联系对方。所有原本发给Alice和Bob的流量现在都流向了Eve。

Ettercap是一个很好的工具,可以让我们轻松执行此攻击。Ettercap还帮助我们劫持TCP连接并操纵发送给接收者的内容。

我们现在开启ARP欺骗,并使用Ettercap开始嗅探网络。然后,我们将从Alice向Bob发送另一个HTTP请求。

根据我们定义的过滤器检测到一些数据包后,Eve将捕获该数据包并操纵网页内容。我们现在可以看到被篡改的有效载荷到达了Alice。

同时,我们可以在Ettercap上看到Alice和Bob之间的连接信息,表明Eve的丢弃操作也是可能的。我们已经成功劫持了TCP连接。

如果你想重现这个演示,可以按照以下GitHub链接中的详细说明进行操作。

总结

本节课中,我们一起学习了TCP连接劫持攻击的基本原理和演示过程。我们了解到,攻击者可以通过ARP欺骗成为通信双方的中间人,进而监听、篡改或中断已建立的TCP连接。这种攻击凸显了在不安全的网络环境中,即使使用TCP这样的可靠协议,通信内容也可能被恶意第三方操纵的风险。理解此类攻击有助于我们更好地认识网络安全威胁,并采取相应的防护措施。

课程 P116:第三层网络攻击详解 🔍

在本节课中,我们将学习针对第三层(即IP网络)的几种常见攻击方式。这些攻击虽然原理简单,却能对网络造成严重影响。我们将重点探讨ICMP重定向攻击和BGP劫持攻击,并通过实例了解其运作机制与潜在危害。

ICMP重定向攻击 🎯

上一节我们概述了第三层攻击,本节中我们来看看第一种具体攻击类型:ICMP重定向攻击。ICMP(互联网控制消息协议)原本用于在网络中传递状态信息,例如通知源主机数据包的TTL(生存时间)已耗尽或目的不可达。然而,攻击者可以恶意利用ICMP的重定向功能。

合法ICMP重定向的工作原理

首先,了解合法的ICMP重定向如何工作,有助于理解攻击者的利用方式。

假设Alice连接到其公司网络,该网络通过路由器1接入公共互联网。Alice想给同公司的同事Bob发送数据包。Alice的计算机默认将路由器1配置为默认网关。因此,发往不同子网的数据包会先发送给路由器1。

但实际上,发往Bob的数据包应该通过路由器2路由。当数据包到达路由器1时,路由器1发现该数据包需要从接收它的同一接口发回。这提示路由器1,Alice将数据包发送给了错误的路由器。

于是,路由器1执行两个操作:

  1. 将数据包转发给正确的下一跳,即路由器2。
  2. 向Alice的计算机发送一个ICMP重定向消息,告知她未来发送给Bob的数据包应直接通过路由器2发送。

Alice的计算机收到此消息后,会在其本地路由表中添加一条新的路由条目。下次Alice再向Bob发送数据包时,她的计算机会直接将其发送给路由器2。

攻击者如何利用ICMP重定向

攻击者可以伪造并发送ICMP重定向消息。例如,攻击者可以向Alice发送一条ICMP重定向消息,声称前往特定IP前缀(比如Bob所在的网络)的最佳路径是通过攻击者自己的计算机。

结果,当Alice尝试与Bob通信时,她的数据包会被错误地发送给攻击者。攻击者可以选择:

  • 丢弃数据包:导致Alice无法与Bob通信(拒绝服务攻击)。
  • 查看并转发数据包:在Alice和Bob之间充当中间人,窃听或篡改通信内容(中间人攻击)。

BGP劫持攻击 🌐

接下来,我们探讨另一种更复杂、影响范围更广的攻击:BGP(边界网关协议)劫持攻击。BGP是互联网核心的路由协议,负责在不同自治系统(AS)之间交换路由信息。

BGP的安全漏洞

BGP攻击利用了该协议的一个或多个安全漏洞:

  1. 地址所有权验证缺失:一个AS可以宣告它并不拥有的IP地址前缀。这意味着它可以宣告属于其他AS的IP地址,从而引发路由混乱。
  2. AS路径验证缺失:接收方AS无法验证宣告的AS路径是否真实有效。BGP路由器无法知道所宣告的AS序列是否真的能到达正确的目的地。
  3. 会话安全依赖:ISP之间通过普通的TCP会话交换BGP消息。如果攻击者能够接管这个TCP会话,或在未被察觉的情况下向会话中注入数据包,就可以宣告错误的AS路径,从而劫持部分地址空间。

令人惊讶的是,即使在今天,几乎任何ISP(无论是意外还是恶意)通过宣告错误路由,都可能使互联网部分瘫痪。

著名的BGP攻击案例

以下是历史上一些因BGP问题导致重大网络故障的著名案例:

  • 2008年巴基斯坦电信YouTube事件:巴基斯坦电信试图在境内屏蔽YouTube,但其错误配置导致虚假的BGP路由宣告泄露到全球互联网,致使YouTube在全球范围内瘫痪数小时。
  • 2004年马来西亚Data One攻击雅虎:马来西亚的ISP Data One被认为发动了恶意攻击,成功劫持了雅虎位于圣克拉拉的两个IP前缀,导致雅虎数据中心无法运作。
  • 2003年垃圾邮件发送者劫持IP地址:垃圾邮件发送者故意劫持了美国政府承包商Northrop Grumman的一块IP地址空间,并利用这些地址发送大量垃圾邮件。
  • 2004年土耳其Titinat事件:土耳其ISP Titinat向全球宣告了完整的BGP路由表,声称土耳其是通往互联网所有地方的最佳路径,导致全球互联网流量试图经由土耳其路由,造成数小时的网络混乱。
  • 2008年巴西CTVC未遂事件:巴西的CTVC几乎发送了会劫持几乎所有运营商IP地址块的完整BGP路由表,幸运的是,一个BGP监控系统及时发现了问题。

BGP劫持攻击原理

让我们通过一个场景具体了解BGP劫持是如何发生的:

假设Alice位于AS1,她想与位于遥远AS3中的Bob(IP前缀为A)通信。正常情况下,Alice的邻居AS2会正确宣告,前往AS3中Bob的最佳路径是通过AS2。

现在,攻击者控制了恶意自治系统ASEvil。一旦攻击者掌控了ASEvil与AS2之间的BGP会话,他就可以宣告虚假的AS路径。例如,他可以宣告一条路径,声称16位的前缀171.64.0.0/16(假设这是Bob所在网络的更大范围)可以通过ASEvil到达。

AS1无法验证这条信息的真伪,因此可能开始将原本发往Bob的流量路由到ASEvil。攻击者可以选择丢弃所有数据包(黑洞攻击),也可以建立中间人攻击,在Alice和Bob不知情的情况下窃听或篡改通信。

为了不引起过多怀疑,攻击者不必劫持整个/16前缀。他可以注入一个更具体的/24前缀(例如171.64.74.0/24),这样只会将属于该更小子网的部分流量引流到攻击者的AS。

本节课中我们一起学习了两种主要的第三层网络攻击。ICMP重定向攻击利用了网络设备间信任的ICMP协议消息,将受害者流量导向攻击者。BGP劫持攻击则利用了互联网核心路由协议BGP在验证和信任模型上的根本性漏洞,允许攻击者宣告虚假路由,从而劫持或干扰大规模的网络流量。这些攻击揭示了网络协议在设计时对可扩展性和效率的追求,有时会以牺牲安全性为代价。

网络安全课程 P117:拒绝服务攻击 (DoS/DDoS) 🛡️

在本节课中,我们将学习拒绝服务攻击。这是攻击系列视频的最后一节,我们将探讨攻击者如何通过耗尽目标资源,使其无法为合法用户提供服务。

概述:什么是拒绝服务攻击?

拒绝服务攻击旨在阻止某项服务正常可用。最简单的攻击方式是向服务器或网络发送过量数据包,使其无法正常运行并服务合法客户端。

攻击者希望最大化每个数据包对服务器造成的资源消耗,包括网络带宽、CPU和内存。分布式拒绝服务攻击之所以有效,是因为攻击流量来自四面八方,难以通过过滤单一来源来阻止。


DDoS攻击的动机与实施

上一节我们介绍了DoS的基本概念,本节中我们来看看攻击者实施DDoS攻击的动机和常见方式。

攻击者通常通过恶意软件以半自动方式渗透大量机器,将其变为“僵尸主机”。随后,攻击者可以命令这些僵尸主机同时向特定目标(如Yahoo.com)发送海量数据包。

以下是攻击者发动DDoS攻击的几个主要原因:

  • 敲诈勒索:攻击者可能威胁某些公司(如离岸赌博网站),要求支付赎金,否则将攻击使其网站瘫痪。
  • 报复:例如,垃圾邮件发送者曾对一家名为Blue Security的反垃圾邮件公司发动DDoS攻击,导致其永久关闭。
  • 炫耀:有些人发动攻击只是为了炫耀技术能力。


各网络层次的拒绝服务攻击

拒绝服务攻击可以发生在网络协议栈的不同层次。从物理层到应用层,都存在相应的攻击手法。

物理层与链路层攻击

在物理层,攻击者可以通过干扰无线信号使网络瘫痪。例如,使用廉价的无线电话或自制简单电路即可实现。

在链路层,可以利用协议特性进行攻击。例如,在802.11无线网络中,存在一种称为网络分配矢量(NAV)的机制,用于指示网络何时空闲。攻击者可以反复使用该机制,长时间“预定”网络,从而有效阻止其他设备传输数据。

网络层攻击

网络层的一个经典攻击是洪水Ping攻击。攻击者可以向目标发送大量ICMP回显请求数据包。

ping -f victim.com

此命令会以最快速度向victim.com发送ICMP请求,试图使其过载。

攻击者更希望实现“攻击放大”,即用较小的攻击成本,消耗目标服务器更多的资源。DNS放大攻击就是此类攻击的典型。

DNS放大攻击原理
攻击者向互联网上大量开放的DNS解析器发送伪造的DNS查询请求,并将请求的源IP地址伪造成受害者的IP地址。这些查询请求通常很小(例如60字节),但请求的DNS记录(如EDNS记录)可能触发巨大的响应(例如3000字节)。这样,攻击者就实现了带宽的放大。

攻击流量放大倍数 ≈ 响应大小 / 请求大小

由于响应数据包是从DNS服务器直接发送给受害者,攻击者的真实身份被隐藏,使得防御和追踪变得困难。

另一种著名的网络层攻击是Smurf攻击。它利用了ICMP协议支持向IP广播地址发送Ping请求的特性。攻击者向一个拥有众多主机的网络广播地址发送伪造的Ping请求(源IP设为受害者地址),该网络内的所有主机都会向受害者回复ICMP响应,从而实现攻击放大。

传输层攻击

传输层最著名的攻击是SYN洪水攻击。它利用了TCP协议的三次握手过程。

  1. 客户端向服务器发送SYN包。
  2. 服务器回复SYN-ACK包,并为这个“半开连接”分配资源(存入哈希表)。
  3. 服务器等待客户端回复最终的ACK包以完成握手。

攻击者持续向目标服务器发送大量SYN包,并且使用伪造的源IP地址。服务器会为每个SYN包分配资源并回复SYN-ACK,但由于源地址是伪造的,永远不会收到ACK回复。服务器的连接表很快被这些“半开连接”占满,导致无法接受新的合法连接。

在2000年代初期,仅需每秒几百个SYN包就足以使大多数服务器瘫痪。

一个真实案例是MS Blaster蠕虫,它向windowsupdate.com的80端口发送SYN洪水攻击,每秒约50个数据包。这导致受感染的客户端无法连接到Windows更新服务器来获取补丁。微软最终不得不更改更新服务器的域名,并借助高带宽的内容分发网络(Akamai)来缓解攻击。

其他传输层攻击还包括:

  • IP分片洪水攻击:发送大量IP分片数据包,但从不发送完整数据包的其他部分,迫使服务器为等待重组而消耗资源。
  • UDP回声攻击:利用UDP端口7上的回声服务。如果两台主机都开启了此服务,攻击者可以伪造从一台主机端口7发往另一台主机端口7的数据包,引发两者之间无限循环的流量往返,直到有数据包被丢弃。合理的防御是,回声服务应忽略源端口也是7的数据包。

应用层攻击

应用层攻击的特点是,客户端的一个简单操作,可能消耗服务器不成比例的巨大资源。

  • DNS over TCP攻击:DNS协议支持TCP。在TCP模式下,客户端先发送一个16位的长度字段,指示后续请求的大小。某些DNS服务器实现会阻塞式地读取指定长度的数据。如果攻击者发送一个很大的长度值,但随后不发送或只发送很少的数据,就会导致DNS服务器挂起等待,消耗其资源。
  • SSL/TLS攻击:建立SSL/TLS连接时,服务器需要进行成本较高的非对称解密运算。攻击者通过发送大量伪造的连接请求,可以消耗服务器大量的CPU资源,而攻击者自身的开销则小得多。


总结

本节课我们一起学习了拒绝服务攻击。我们了解到,DoS/DDoS攻击的核心目标是破坏服务的可用性。攻击可以发生在网络协议栈的各个层次,从物理干扰到利用协议特性(如TCP三次握手、DNS查询、ICMP广播),再到针对特定应用(如DNS、SSL)的漏洞。

攻击者常利用“放大”效应,以较小的自身代价对目标造成巨大冲击,并通过分布式僵尸网络和IP地址伪造来隐藏自身,增加防御难度。理解这些攻击原理,是构建有效防御措施的第一步。

课程 P118:网络安全基础原理 🔐

在本节课中,我们将要学习网络安全的核心原则。我们将探讨如何在一个充满威胁的网络环境中,保护计算机系统的通信安全。课程将围绕三个核心安全属性展开,并介绍实现这些属性的基本密码学方法。


威胁模型与防御方法

上一节我们介绍了网络世界充满危险。本节中我们来看看如何定义威胁并构建防御。

一个威胁模型基于我们已了解的所有攻击方式。攻击者可以监听你的所有流量、丢弃你的任何数据包、重放数据包,甚至生成看似来自你的主机或应用程序的新数据包。

为了防御这些攻击,我们将采用两种主要方法。

第一种方法是密码学。它使得通信双方能够进行端到端的安全通信,尽管中间的网络是不安全的。密码学字面意思是“对密码的研究”,它是一套基于“秘密”概念以及“在没有秘密的情况下理解数据的计算难度”的数学工具。

以密码学为基础,事实证明,即使攻击者可能控制并拥有整个网络,我们也能构建端到端的安全通信。这里的“安全”意味着攻击者无法重写我们的消息、生成新消息或窥探我们的消息。

第二种方法是防止攻击者阻塞你的消息。即使两台主机可以安全通信,攻击者也可能完全阻止它们通信。解决此问题的通用方法是设计可扩展的系统。以DNS为例,其拥有众多根服务器,其中一些被高度复制,这意味着很难对其发起拒绝服务攻击。

可扩展系统设计本身是一个复杂的话题,值得开设一门完整的课程。因此,本课程将聚焦于问题的网络部分:安全通信


密码学:安全通信的基石

上一节我们提到了密码学是防御的核心。本节中我们来深入了解密码学的基本概念。

密码学是一套用于保护通信安全的数学原理和思想。关于密码学最重要的一点是,它非常微妙且注重细节。如果你的系统中存在一个缺陷,那么它就是不安全的。因此,不加思索地应用密码学不太可能使你的系统安全。

与其发明全新的安全系统,使用经过测试、被充分理解的现有系统要安全得多。安全概念经常被误用或误解,例如有人认为消息认证码这种安全原语具有与CRC相同的错误检测属性。

密码学可以为我们提供三样宝贵的东西。

以下是密码学提供的三个核心价值:

  1. 保密性:这是与另一方私下通信的能力,确保其他任何人都无法读取。密码学通过加密来提供保密性。
  2. 完整性:这是判断我们的消息是否被篡改的能力。根据具体需求和使用的密码学类型,有多种提供完整性的方法。未来的视频将深入介绍三种基本机制:密码学哈希密码学签名消息认证码
  3. 真实性:这是一方证明其身份的能力。未来的视频将深入介绍真实性的三种基本机制:证书消息认证码密码学签名

再次强调,密码学可以使你的系统安全,但前提是你必须谨慎且正确地使用它。犯错误非常容易。不要信任那些看起来事后才添加安全措施的系统,也不要认为构建一个安全的系统是容易的。


核心安全属性详解

上一节我们概述了密码学的三大价值。本节中我们将逐一详细探讨这些核心安全属性。

保密性

第一个属性是保密性。其理念是通信双方应能秘密交换信息,即使他人能读到消息,也无法理解其内容。这在发送信用卡号等场景中非常有用。

一个具有完美保密性的密码系统称为一次性密码本。其思想是,你和我共享一个完全随机的0和1密钥K,没有其他人拥有这个一次性密码本。为了向你发送消息M,我只需将消息M与密钥K进行异或运算,生成密文C:C = M XOR K。然后我将C发送给你。为了重建M,你只需将C与K再次进行异或运算:M = C XOR K

一次性密码本是完美安全保密性的一个例子。如果一次性密码本是完全随机的,那么给定任何C,任何M出现的可能性都相等。它也非常快,你只需要做异或运算。但一次性密码本并不实用,因为K必须至少与M一样长。如果我想与你交换100兆字节,我需要一个100兆字节的K。

因此,在实践中,提供保密性的密码系统试图提供算法,使我们能够交换一个小得多的K(例如128位或256位),使得可能的密文数量达到2128或2256,从而确保安全。

完整性

第二个属性是完整性。完整性是交换消息并确信它们未被篡改或更改的能力。例如,当我下载软件时,我想知道它是真正的版本,而不是一个在我的机器上安装恶意软件的破解版本。

某些形式的完整性还允许你知道是对方发送了消息。如果双方共享一个秘密密钥,那么存在一些完整性形式,只有拥有秘密密钥的人才能正确执行。

两种非常常见的完整性形式是密码学哈希消息认证码

密码学哈希是将任意长度的数据转换为固定长度哈希值的函数,就像普通的哈希函数一样。但密码学哈希具有额外的抗碰撞属性。如果我有一个消息X及其哈希值H(X),那么对于他人来说,找到一个与X不同但具有相同哈希值的消息Y是计算上不可行的。这意味着,例如,如果我知道我想要下载的程序的密码学哈希值,那么他人以某种方式篡改软件并使其具有相同哈希值是计算上不可行的。

消息认证码类似于密码学哈希,不同之处在于它们使用一个密钥K来生成和验证MAC。任何人都可以生成密码学哈希,但只有拥有K的人才能计算出正确的MAC。对于MAC,除非你拥有密钥K,否则生成消息的正确MAC是计算上不可行的。因此,如果我们事先交换了密钥K,并且收到了带有正确MAC的消息,那么我就知道没有人篡改过消息,并且是你生成了这个MAC。

真实性

第三个属性是真实性。这是验证某人是否是其声称身份的能力。例如,你收到一条据称来自教务长的消息,并希望确认教务长确实发送了它。

如果你和教务长事先交换了一个秘密,那么你可以使用消息认证码来实现这一点。如果你收到一条带有正确MAC的消息,并且该MAC是用你与教务长共享的秘密计算的,那么你就知道是教务长发送了它。

如果你没有共享秘密,那么你可以使用信任链。如果你信任一方,那么该方可以为另一方担保。这第二方又可以担保第三方,依此类推。例如,假设我们有一些信息可以验证Veracine的真实性。Veracine可以为斯坦福大学担保,而斯坦福大学可以为教务长担保。


高可用性系统设计

上一节我们讨论了如何确保通信内容的保密、完整与真实。本节中我们来看看如何确保通信服务本身可用。

最后,是如何设计具有高可用性的计算机系统,使其能够抵抗拒绝服务和分布式拒绝服务攻击。攻击种类繁多,包括复制攻击、资源耗尽攻击、ping攻击、僵尸网络攻击等。

一般来说,你可以通过两种方式应对:扩展你的系统,使其能够分布负载并处理攻击;或者在某个上游节点过滤流量。例如,如果有人对你的电缆调制解调器发起DDoS攻击,你可以联系你的互联网服务提供商,请求过滤掉指向它的攻击流量。


本节课中我们一起学习了网络安全的基础原理。我们首先定义了威胁模型,并介绍了两种核心防御方法:密码学和可扩展系统设计。接着,我们深入探讨了密码学如何提供保密性、完整性和真实性这三大安全属性,并解释了每种属性的基本实现机制,如加密、哈希和消息认证码。最后,我们简要提及了通过可扩展设计和流量过滤来保障系统可用性的思路。理解这些基本原则是构建和评估安全网络系统的第一步。

课程 P119:密码学三要素之一 —— 保密性 🔒

在本节课中,我们将要学习密码学能够提供的三个核心属性中的第一个:保密性,它也被称为机密性

保密性的基本实现方式是通过加密。由于密码学建立在坚实的数学基础之上,并且精确地使用它至关重要,我们将引入一些关键术语来避免因随意使用而带来的风险。

对称加密的基本概念

上一节我们介绍了保密性的目标,本节中我们来看看实现它的基础方法:对称加密。

在对称加密中,通信双方共享一个秘密密钥 K。假设我们有一个需要保密传输的消息 M 和密钥 K

  • M 被称为明文纯文本,即我们希望保密的内容。
  • 为了加密,我们调用一个加密函数 e,传入明文 M 和密钥 K。这会生成一个密文 C
  • 如果我们的加密算法是安全的,那么对于没有密钥的人来说,从密文 C 推导出明文 M 在计算上是不可行的。
  • 因此,我们可以通过网络传输密文 C。攻击者可以看到它,但无法读取原始消息 M
  • 为了解密密文,我们调用解密函数 D,同样传入密钥 K。这将返回原始的明文 M

整个过程的目标是:只有拥有正确密钥 K 的人才能解密消息或了解其任何信息。当然,攻击者可以尝试每一个可能的 K,因此我们需要选择一个足够大的密钥空间,使得穷举搜索变得不可行。例如,使用 128 位或 256 位的密钥。

因为加密函数 E 和解密函数 D 使用相同的密钥 K,所以我们称之为对称加密共享密钥加密。还有其他不使用对称密钥的密码系统,我们将在后续课程中介绍。

以下是常见的对称加密算法示例:

  • AES
  • Blowfish
  • DES
  • RC4

一次性密码本:完美但受限

了解了通用的对称加密后,我们来看一个理论上完美但实践中受限的特殊算法:一次性密码本。

一次性密码本是一种具有完美保密性但通常不实用的加密算法。其工作原理如下:

  1. 我们生成一个完全随机的比特流作为密钥 K。发送方和接收方需要事先通过某种安全方式交换这个密钥(例如,通过握手和U盘传递)。
  2. 为了加密,我们将明文 M 与密钥 K 进行异或运算。
    • 加密公式:C = M ⊕ K
  3. 为了解密,我们将密文 C 与相同的密钥 K 再次进行异或运算。
    • 解密公式:M = C ⊕ K

这个算法是完美安全的,因为如果我们只有密文而没有密钥,那么任何可能的明文 M 都同样可能是正确的。此外,这个算法非常快,因为它只需要进行异或操作。

因此,如果你是一个需要发送短消息的超级秘密间谍,一次性密码本非常棒。但在一般实践中并非如此。一次性密码本的主要问题是:你的密钥 K 必须和消息 M 一样长。要发送 1GB 的数据,就需要一个 1GB 长的密钥,这显然不实用。

我们更希望使用小的密钥来加密大量的数据,同时仍然保证密码难以被破解。


本节课中我们一起学习了密码学的第一个核心属性——保密性。我们介绍了通过对称加密实现保密性的基本模型,明确了明文密文密钥的概念。我们还探讨了理论上完美的一次性密码本算法及其在实践中的局限性,即密钥长度必须等于消息长度。在实际应用中,我们追求的是用短密钥安全地加密长数据。

课程 P12:字节序与网络数据 🧩

在本节课中,我们将学习计算机如何存储多字节数据(字节序),以及为什么在网络通信中统一字节序至关重要。我们还将了解如何编写与处理器架构无关的网络代码。


为什么字节序重要?🤔

上一节我们介绍了字节序的基本概念。本节中我们来看看为什么它在网络通信中如此关键。

如果两台计算机需要通信,它们必须就使用大端序还是小端序来表示数字达成一致。这是因为不同的处理器使用不同的字节顺序。例如,英特尔和AMD的x86处理器使用小端序,最低有效字节在前。相反,ARM处理器和iPhone等设备使用大端序,最高有效字节在前。

我们不希望两台计算机去关心或了解对方使用的是大端序还是小端序。因此,协议规范通常选择一种字节序并始终坚持。对于互联网,这意味着大端序。所有互联网协议规范都使用大端格式。


如何检测字节序?🔍

以下是检测你的计算机是大端序还是小端序的一段C代码示例。

#include <stdio.h>

int main() {
    int num = 1;
    // 将整数指针转换为字符指针,以便逐个字节查看
    char *byte = (char *)#
    if (*byte == 1) {
        printf("小端序\n");
    } else {
        printf("大端序\n");
    }
    return 0;
}

这段代码接受一个整数值,并将其转换为字符指针,从而允许代码单独查看其字节。如果索引为0的字节是1,这意味着最低有效字节在前,计算机是小端序。如果索引为0的字节是0,则计算机是大端序。


网络通信中的字节序转换 🔄

这带来了一个复杂性:互联网数据包需要以大端序格式存在。但如果你的处理器是小端序的,就会产生问题。

例如,假设你想将TCP段的端口号设置为80(HTTP端口)。一种简单的方法是创建一个C结构体,其中包含一个在正确偏移量的port字段。但如果你将值80赋给port字段,在小端序机器上,80会被存储为0x50作为第一个字节。而大端序要求0x50存储在第二个字节。

所以,尽管数据包中的port字段值是80,你的值也是80,但直接比较可能失败。

为了使这更容易,网络库提供了在主机字节序和网络字节序之间转换的实用函数。

以下是核心转换函数:

  • htons():将16位(短整型)主机字节序值转换为网络字节序。
  • ntohs():将16位网络字节序值转换为主机字节序。
  • 对于32位(长整型)值,也有对应的htonl()ntohl()函数。

因此,检查数据包端口是否为80的正确方法是:读取数据包结构中的端口字段,调用ntohs()将其从网络字节序转换为主机字节序,然后将其与80进行比较以获得正确结果。

在小端序架构上,htonsntohs会反转两个字节的顺序。在大端序架构上,它们只是原样返回值。这些函数为你提供了编写与处理器架构无关的网络代码的机制。

但是请注意:每当处理网络数据时都要格外小心。如果你在主机和网络字节序之间转换时不够严格和规范,会给自己带来巨大的麻烦。你可能忘记转换,或者无意中转换了两次。突然之间,你的协议行为就会不正确,触发各种奇怪的错误。这种情况确实经常发生。

因此,你应该尽可能避免这种情况,并谨慎使用这些转换函数。


互联网协议格式 📄

现在我们知道互联网规范如何布局网络中的多字节值(即大端序),我们可以看看互联网规范如何描述它们的数据包格式。

出于历史原因,互联网规范是用纯ASCII文本编写的。左侧的块文本直接来自RFC 791,它指定了互联网协议版本四(IPv4)。顶部显示从0到31的位。数据包被写成四字节宽,因为IPv4有五行必需的字段,这意味着一个IPv4头部至少是20字节长。

我们经常使用更简单的视觉格式来显示像右侧这样的数据包。例如,一个IPv4数据包的“总长度”字段是两字节(16位)长,这意味着一个IPv4数据包不能超过65,535字节。该字段在数据包中以大端格式存储。一个1400字节的数据包长度将被存储为十六进制0x0578

所以,那个长度的IP数据包的第三个字节是十六进制0x05

让我们在Wireshark中看看。启动Wireshark并监听数据包。第一个数据包是用于TLS(传输层安全)的,它是网页浏览器用于安全连接的。HTTPS TLS向我们隐藏了数据包的数据,但我们仍然可以使用Wireshark看到其头部。我们可以看到,TLS负载位于TCP段的端口443(标准TLS端口)内部。这个TCP段又在IPv4内部。

详细查看IPv4头部,我们可以看到数据包总长度字段是1230。1230的十六进制是0x04CE(4 * 256 + 206)。在底部,Wireshark向我们显示数据包的实际字节,这就是04 CE,以大端(网络)顺序存储。


总结 📝

本节课中我们一起学习了:

  1. 字节序的重要性:不同的处理器使用不同的字节序(大端序或小端序),网络通信需要统一标准(互联网使用大端序)。
  2. 检测方法:可以通过C代码检测当前系统的字节序。
  3. 网络编程实践:使用htons()ntohs()等函数在主机字节序和网络字节序之间进行转换,以编写架构无关的代码。必须谨慎使用,避免错误转换
  4. 协议格式:互联网协议(如IPv4)规范使用大端序定义多字节字段,我们可以使用工具(如Wireshark)查看和分析网络数据包的实际字节布局。

你已经看到了处理器如何以不同的方式布局数字,但由于网络数据包需要达成一致,协议规范决定了如何在其数据包中布局数字。这可能与你的处理器不同。为了帮助你处理这个问题,C网络库提供了辅助函数来在主机和网络字节序之间转换数据,但请谨慎使用。随意使用它们很容易导致你在调试中浪费许多时间,这可以通过谨慎来防止。

课程P120:一次性密码本密钥复用风险 🔑

在本节课中,我们将要学习一次性密码本加密算法中一个关键的安全概念:密钥复用。我们将通过一个具体的例子,分析当同一个密钥被用来加密多条消息时,会泄露哪些信息。

上一节我们介绍了理想的一次性密码本加密。本节中我们来看看,如果违背了“一次性”的使用原则,会发生什么。

场景设定

假设你生成了一个完全随机的密钥 K。你用这个密钥,通过一次性密码本算法加密了两条消息 M1M2

加密过程遵循以下公式:

C1 = K XOR M1
C2 = K XOR M2

其中,C1C2 分别是消息 M1M2 对应的密文。

密钥复用导致的信息泄露

现在,关键问题来了:攻击者同时获得了密文 C1C2,这会泄露关于原始消息 M1M2 的信息吗?

答案是肯定的。尽管密钥 K 本身是完美随机的,但重复使用它,会将两条消息联系起来。

我们可以通过数学推导来理解这一点。根据加密公式,我们可以进行如下操作:

C1 XOR C2 = (K XOR M1) XOR (K XOR M2)

由于异或运算满足结合律和交换律,且同一个值异或两次等于零(K XOR K = 0),上式可以简化为:

C1 XOR C2 = M1 XOR M2

这个结果 M1 XOR M2 就是泄露的信息。攻击者虽然不能直接得到 M1M2,但获得了它们异或后的结果。

以下是这个结果可能带来的风险:

  • 结构暴露:如果其中一条消息(例如 M1)的部分内容被猜测或已知(比如标准的文件头、问候语),攻击者可以立即计算出另一条消息(M2)的对应部分。
  • 模式分析:两条消息之间的关系被暴露。例如,如果两条消息在相同位置有相同的单词或字符,那么异或结果在该位置就会是0,这可能会暴露消息的语言特征或格式。
  • 完全破解:在极端情况下,如果其中一条消息被完全破解,那么另一条消息也会随之被完全解密。

核心要点总结

本节课中我们一起学习了密钥复用在一次性密码本中的危害。

  • 一次性密码本的核心安全前提是密钥绝对只使用一次。
  • 当同一个密钥 K 用于加密多条消息时,即使密钥本身随机,密文的组合(如 C1 XOR C2)也会直接泄露原始消息之间的关系(即 M1 XOR M2)。
  • 这种泄露为攻击者提供了破解的突破口,彻底破坏了一次性密码本理论上具备的完美保密性。

因此,确保每个密钥只使用一次,是使用一次性密码本时不可妥协的原则。

课程 P121:一次性密码本的安全性 🛡️

在本节课中,我们将探讨一次性密码本加密方案的安全性。我们将分析,如果同一个密钥被重复使用来加密不同的消息,会带来怎样的安全风险。


概述

一次性密码本是一种理论上绝对安全的加密方法,但其安全性依赖于一个关键前提:密钥必须只使用一次。本节课程将通过一个具体的例子,展示当同一个密钥被重复使用时,窃听者如何利用两次密文来获取原始消息的信息。

上一节我们介绍了理想加密的概念,本节中我们来看看如果违背了“一次性”原则会发生什么。


密钥重用导致的信息泄露

答案是肯定的,存在安全风险。如果一个名为 Eve 的窃听者同时截获了两次使用相同密钥 K 加密的密文 C1C2,她可以尝试进行重构。

以下是窃听者 Eve 的推理和计算过程:

  1. 获取两次密文

    • 第一条消息 M1 的密文:C1 = M1 XOR K
    • 第二条消息 M2 的密文:C2 = M2 XOR K
  2. 对两个密文进行异或操作

    • Eve 计算 C1 XOR C2
    • 根据公式推导:
      C1 XOR C2 = (M1 XOR K) XOR (M2 XOR K)
      
      由于异或运算满足结合律和交换律,且 K XOR K = 0,上式可以简化为:
      C1 XOR C2 = M1 XOR M2
      
    • 这意味着,两次密文的异或结果,等于两次原始明文的异或结果。密钥 K 在计算中被抵消了。

  1. 分析结果
    • 虽然 Eve 没有得到 M1M2 本身,但她得到了 M1 XOR M2
    • 如果 M1M2 都是 ASCII 文本消息,那么 M1 XOR M2 的结果会泄露大量关于原始消息的信息。通过分析字符频率、空格位置等模式,攻击者有可能推断出部分或全部明文内容。

一个简单的例子

让我们通过一个极端但清晰的例子来理解这种风险。

假设巧合的是,两条原始消息完全相同,即 M1 等于 M2

那么根据上面的公式,C1 XOR C2 的结果将是 M1 XOR M1,这等于全零。更直接的是,Eve 会发现 C1C2 是完全相同的。

这样一来,Eve 立刻就能推断出“两条原始消息一模一样”这一重要信息。这完全违背了加密的保密性原则。


核心总结

本节课中我们一起学习了一次性密码本加密的核心安全准则。

其名称“一次性”密码本就包含了最重要的使用规范:一个密钥只能使用一次。本节课的推导证明,如果同一个密钥被用来加密多条消息,即使该密钥本身是随机的且长度与消息相等,攻击者也能通过对比密文获得关于明文的宝贵信息,从而导致整个加密体系失效。

因此,确保密钥的绝对一次性使用,是维护该加密方案理论安全性的唯一途径。

课程 P122:对称加密基础 🔐

在本节课中,我们将学习对称加密的基本概念,了解一次性密码本在实际应用中的局限性,并探索两种主流的对称加密类型:流密码和分组密码。我们还将以Blowfish算法为例,简要了解分组密码的工作原理。


一次性密码本通常不切实际。因此,我们需要一种密码系统,能够分发一个较小的密钥,例如128或256位。

我们通过某种方式预先共享这个密钥,例如通过电话沟通,或者在握手时写下并交换。然后,我们使用这个密钥 k 来加密一个更长的消息 M

我们调用加密函数 E,传入明文消息 M 和密钥 k,生成密文 C

现在,与一次性密码本不同,可能只有一个可能的 M 能产生这个密文 C。但我们相信,通过计算找到这个 M 是可行的。你可以尝试所有可能的密钥,但要解密 2^256 个密钥中的一个,将需要极其漫长的时间。

假设解密一条消息只需要一条指令。再假设你的处理器核心是4GHz,并且你的处理器有40亿个核心。我们仍然需要40亿台这样的计算机,花费31年,才能解密这样一条消息。


上一节我们讨论了对称加密的必要性,本节中我们来看看对称密码的两种主要类型:流密码和分组密码。

对称密码主要有两种类型:流密码和分组密码。

流密码基于密钥生成一个伪随机密码流,即一个伪随机的比特序列。然后,我们通过与这个流进行异或(XOR)操作来加密或解密,类似于一次性密码本。但它并非真正的一次性密码本。如果有人声称它是,请立即对其表示怀疑,因为他们并不了解自己在谈论什么。

一般来说,流密码在实践中遇到了许多问题。流密码的问题通常源于重复使用。例如,如果我们重用相同的伪随机比特序列(即在不同消息中重用相同的密钥),那么攻击者就可以发起类似于“两次密码本”的攻击。

例如,最初的Wi-Fi加密协议WEP就使用了流密码。大约在2001年Wi-Fi开始普及时,它被证明存在漏洞,并在2003至2004年间被WPA取代。现在的WPA2使用了一种称为分组密码的技术。

分组密码对固定大小的数据块进行操作,例如64位或128位。分组密码将明文块映射为密文块。存在许多种分组密码。如今,通常应该使用AES(高级加密标准)。


了解了分组密码的概念后,接下来我们通过一个具体例子来感受其工作原理。我将简要介绍一种分组密码Blowfish的基本原理,但请注意:我并非完整解释整个算法,只是试图让你感受一下分组密码的外观和工作方式。我省略了许多细节,如果不注意这些细节,密码可能就不安全。你应该依赖现有的实现和使用建议。

以下是Blowfish分组密码的基础知识。它使用了一种称为Feistel网络的结构。

Feistel网络或Feistel密码是一种加密和解密使用相同计算结构的密码。具体来说,解密Blowfish看起来就像是加密的逆过程,只是函数 F 有所不同。因此,要解密,如果你从底部的密文 C 开始,反转所有箭头,明文 M 就会从顶部输出。

使用Blowfish时,你获取原始密钥并推导出函数 F 和18个子密钥 P1P18。你取64位的明文块,并将其分成两部分:左半部分 L0 和右半部分 R0L0R0 都是32位长。

然后,你通过左侧所示的结构对 L0R0 进行16轮迭代处理。你将左半部分与一个子密钥 P 进行异或。然后将这个值传递给函数 F,并将其结果与右半部分的值进行异或。右半部分的值变成新的左半部分,反之亦然。

在最后一步,你将左半部分的值与 P18 异或,右半部分的值与 P17 异或。这产生两个32位的值,将它们连接起来就形成了密文 C


在本节课中,我们一起学习了对称加密的核心思想。我们了解到一次性密码本虽然理论完美但实践困难,因此需要能使用短密钥加密长消息的密码系统。我们介绍了对称密码的两种主要类型:易因密钥重用而出问题的流密码,以及更现代、更安全的分组密码(如AES)。最后,我们以Blowfish算法为例,初步了解了分组密码通过Feistel网络进行多轮迭代加密的基本过程。记住,实际应用中应使用经过严格验证的现有算法和实现。

课程 P123:Blowfish 简化版安全性分析 🔐

在本节课中,我们将分析一个简化版 Blowfish 加密算法的场景,并尝试推导出特定明文块中的信息。我们将通过一个具体的例子,理解迭代轮数对加密安全性的影响。


上一节我们介绍了 Blowfish 算法的基本结构。本节中我们来看看一个简化版本,并分析其潜在的安全问题。

假设我决定让 Blowfish 算法运行得更快,并将其迭代轮数削减到仅剩一轮。

我向这个简化版的算法输入两个明文块。第一个明文块全部由零组成,并且我的对手以某种方式知道了这个事实。该算法产生了此处显示的第一个密文。

接着,我输入第二个明文块,算法产生了此处显示的第二个密文。

那么,第二个明文块中 L0 的值是多少?

以下是解题所需的已知信息与推导步骤:

  • 已知条件 1:加密算法是仅进行一轮迭代的简化版 Blowfish。
  • 已知条件 2:第一个明文块 P1 是全零块,且对手知晓这一点。
  • 已知条件 3:我们拥有第一个明文块对应的密文 C1
  • 已知条件 4:我们拥有第二个明文块对应的密文 C2
  • 推导目标:求出第二个明文块 P2 的左半部分 L0 的值。

核心推导逻辑基于 Blowfish 的单轮 Feistel 结构。在单轮加密中,对于任意明文块 P = (L0, R0),其加密过程可以简化为:

R1 = F(L0 ⊕ P_arrays[0]) ⊕ R0
L1 = R0

其中,F 是轮函数,P_arrays[0] 是第一轮的子密钥。

由于我们知道第一个全零明文块 P1 = (0, 0) 及其密文 C1 = (L1, R1),我们可以利用这个关系来解出轮函数 F 在特定输入下的输出,进而破解第二个密文。

具体方法是,通过 P1C1 计算出 F(P_arrays[0]) 的值。因为 L0=0, R0=0,所以 R1 = F(0 ⊕ P_arrays[0]) ⊕ 0 = F(P_arrays[0])。而 R1 可以从 C1 中获得。

得到 F(P_arrays[0]) 后,对于第二个密文 C2 = (L1‘, R1’),其对应的右半部分明文 R0‘ 就是 L1‘。接着,我们可以逆向计算左半部分明文 L0‘

L0‘ = F_inverse(R1‘ ⊕ R0‘) ⊕ P_arrays[0]

由于我们已知 F(P_arrays[0]) 的值,并且知道 F 函数在单轮简化模型下可能可逆或可通过已知输入输出对推导,因此可以计算出 L0‘ 的值。


本节课中我们一起学习了如何利用已知明文攻击来分析迭代轮数不足的加密算法。通过一个具体的 Blowfish 单轮简化模型,我们演示了当对手掌握一个已知明文-密文对时,可能如何推导出另一个密文对应的部分明文信息。这强调了在密码学设计中,足够的迭代轮数对于抵抗密码分析至关重要。

课程 P124:Feistel 网络解密实战 🧩

在本节课中,我们将学习如何分析一个简化的 Feistel 网络加密过程,并通过已知的明文和密文片段,推导出未知的明文数据。我们将重点关注异或(XOR)运算在解密过程中的核心应用。


上一节我们介绍了 Feistel 网络的基本结构,本节中我们来看看一个具体的解密计算实例。

观察 L0 在网络中的传递路径。已知第一个明文的 L0 部分是全零。

根据 Feistel 网络的规则,R2 的值由 L0 与第一轮的轮函数输出 P1 进行异或运算得到。其关系可以表示为:

公式:R2 = L0 ⊕ P1

由于我们知道第一个明文的 L0 为 0,这意味着 P1 的值就等于 R2 的值。从图中可知,R2 的值为 0x7B77DCA2

因此,我们得到:
P1 = 0x7B77DCA2


既然我们已经知道了 P1 的值,接下来可以计算第二个明文的 L0 部分。

第二个明文的 R2 值(即密文的一部分)为 0x0DCD85。在 Feistel 网络中,第二轮的 L0 由第一轮的 R2 与 P1 异或得出。以下是计算过程:

公式:L0_second = R2_second ⊕ P1

将数值代入公式:
0x7B77DCA2 ⊕ 0x0DCD85 = 0xEBEA0027

因此,第二个明文的 L0 部分是 0xEBEA0027


为了验证或进行快速计算,我们可以只关注字节的异或运算,而不必进行完整的 32 位计算。以下是快速校验的方法:

观察最低字节的运算:

  • A2 ⊕ 85 的结果是 27(因为 A(1010) ⊕ 8(1000) = 2(0010)2(0010) ⊕ 5(0101) = 7(0111))。

这个快速计算的结果与完整计算得到的 0xEBEA0027 的最低字节 27 相符,验证了我们的推导。


本节课中我们一起学习了如何利用 Feistel 网络的对称性和异或运算的可逆性进行解密。我们通过已知的第一个明文(L0=0)推导出了中间值 P1,进而成功地计算出了第二个未知明文的 L0 部分,最终答案为 A, 0xEBEA0027

核心在于掌握 R2 = L0 ⊕ P1 这一关系,并通过异或运算逆向求解所需值。

课程 P125:分组密码工作模式 🔐

在本节课中,我们将要学习如何将安全的分组密码(如AES)应用于实际中长度不固定的消息。我们将探讨几种不同的工作模式,分析它们如何运作以及为何某些模式比其他模式更安全。


从简单开始:电子密码本模式

上一节我们介绍了安全的分组密码。本节中我们来看看如何用它加密长消息。一个最直接的方法是电子密码本模式

其工作原理非常简单:

  1. 将消息 M 分割成多个固定长度的块,例如 M1, M2, M3, M4
  2. 使用相同的密钥 K,独立加密每个明文块。
    • 加密过程可以表示为:C_i = Encrypt(K, M_i)
  3. 所有密文块 C1, C2, C3, C4 组合起来就是完整的密文。

这种模式速度快,因为所有块的加密可以并行进行,非常适合现代多核处理器。如果加密算法本身是安全的,那么攻击者无法解密任何单个块。

然而,ECB模式存在一个严重的安全缺陷。由于加密是确定性的,相同的明文块总会产生相同的密文块。

以下是ECB模式的问题:

  • 如果 M1 等于 M2,那么 C1 也将等于 C2
  • 例如,在传输稀疏文件时,攻击者可以通过观察重复的密文块,识别出文件中非零数据区域的位置。
  • 视觉上,用ECB加密一张图片(如左图的企鹅Tux),其中相同的区域(如白色背景)会产生相同的密文,导致加密后的图片(中图)仍然能看出原始图像的轮廓,这泄露了信息。我们期望的是像右图那样,密文中看不出任何模式。

因此,ECB模式不能为实际数据提供足够的保密性。


提升安全性:密码块链接模式

为了解决ECB模式暴露模式的问题,我们需要一种方法将每个明文块的加密与之前的结果联系起来。这就是密码块链接模式

在CBC模式中,我们引入一个初始化向量(IV),它是一个与分组长度相同的随机数。

以下是CBC模式的加密步骤:

  1. 将第一个明文块 M1 与 IV 进行异或操作。
  2. 加密异或后的结果,得到第一个密文块 C1
    • 公式表示为:C1 = Encrypt(K, M1 XOR IV)
  3. 对于后续的每个明文块 M_i,先将其与前一个密文块 C_{i-1} 进行异或,然后再加密。
    • 公式表示为:C_i = Encrypt(K, M_i XOR C_{i-1})

IV的使用至关重要。如果只用一个密钥加密一条消息,IV可以设为零。但基本准则是:不要重复使用同一个IV

以下是关于IV的注意事项:

  • 假设你对两条不同的消息重复使用了相同的IV(例如都是0)。
  • 如果这两条消息的明文开头部分相同,那么它们产生的密文开头部分也会相同。
  • 这就向攻击者泄露了“这两条消息开头可能相同”的信息。

当我们将CBC模式应用于之前的企鹅图片时,得到的密文图像(右图)完全掩盖了原始模式,问题得以解决。


其他工作模式简介

ECB和CBC只是使用分组密码的两种方式。还有许多其他模式,各有不同的特性、优点和缺点。

以下是另外几种常见的工作模式:

  • 密码反馈模式:将消息与前一个密文块的加密结果进行异或。这在消息长度不是分组大小的整数倍,且不想填充零时很有用。
  • 输出反馈模式:反复加密IV,将其用作类似流密码的密钥流。
  • 计数器模式:使用密钥加密一个递增的计数器值,然后将输出与明文块进行异或。这种模式非常易于并行化,但通常需要确保每个消息使用的计数器值不重复。

最终测验与总结

现在让我们做一个最后的测验。假设你和通信方共享一个秘密密钥,并使用一个安全的密码算法以CBC模式加密消息,然后通过网络传输这些消息。

这些消息是安全的吗?

答案并非绝对“是”。虽然CBC模式本身能很好地隐藏明文模式,但消息的保密性还取决于其他因素,例如:IV是否唯一且不可预测、密钥是否保持机密、以及通信信道是否还面临其他攻击(如篡改)。

在本节课中,我们一起学习了:

  1. ECB模式:简单、并行化好,但因相同的明文产生相同的密文而不安全,会泄露数据模式。
  2. CBC模式:通过将每个块与前一个密文块链接,有效隐藏了模式。安全使用它的关键是使用唯一且不可预测的初始化向量
  3. 还有其他如CFB、OFB、CTR等工作模式,适用于不同的场景。

选择正确的工作模式并正确使用其参数(如IV),对于构建安全的加密系统至关重要。

课程 P126:加密与完整性 🔐

在本节课中,我们将要学习加密与数据完整性之间的关键区别。我们将探讨为什么仅使用加密技术不足以保护信息不被篡改,并理解保密性与完整性的不同作用。


上一节我们介绍了加密的基本概念,本节中我们来看看加密的具体作用。

加密技术能够提供保密性。这意味着只有拥有正确密钥的授权方才能读取被加密的信息。其核心过程可以用以下公式描述:

密文 = 加密(明文, 密钥)

然而,加密本身并不能保证信息的完整性


理解了加密的局限性后,我们来看看这意味着什么。

即使信息被加密,攻击者仍然可能对其进行修改或破坏。加密过程并不验证信息在传输或存储后是否与原始状态一致。

以下是可能发生的情况:

  • 攻击者可以截获加密的密文。
  • 攻击者可以修改密文中的部分数据。
  • 接收方解密后,可能会得到一份被篡改过的、无意义的或有害的明文信息,而无法察觉信息已被更改。

所以,答案是“不能”。加密提供保密性,但不提供完整性。因此,攻击者仍然可以修改和篡改你的信息。


本节课中我们一起学习了加密与完整性的核心区别。我们明确了加密技术能确保信息的私密性,但无法防止信息被篡改。要构建一个安全的信息系统,通常需要结合使用加密(提供保密性)和消息认证码或数字签名等技术(提供完整性)。

课程 P127:完整性 🔐

在本节课中,我们将要学习计算机安全中的“完整性”概念。我们将探讨为什么仅有加密提供的保密性是不够的,并介绍两种确保数据完整性的核心密码学原语:密码学哈希函数和消息认证码。


概述

加密提供了保密性,但我们也需要完整性。对于一个安全的系统,我们需要知道一条消息确实是由特定方生成的,并且没有被任何人篡改。

例如,假设我们想要一个安全的文件系统协议。如果没有完整性,攻击者可能会向写入命令附加垃圾数据,甚至可能创建包含垃圾数据的新写入命令。

核心要点是:仅有保密性是不够的。加密可以防止他人读取我们的消息,但它不能保护消息免受篡改。除了保密性之外,安全系统的第二个属性就是完整性。


完整性的重要性 🛡️

上一节我们概述了完整性的必要性,本节中我们来看看它的具体应用场景。

完整性算法让你确信一条消息是由拥有密钥的人生成的。因此,假设密钥是保密的,你就可以确信消息来自特定的程序、主机等。这非常有用。

以下是完整性的一些关键应用场景:

  • 网络路由:你可以知道一个路由向量确实来自声称发送它的节点,而不是攻击者试图诱骗你将流量路由到他们那里。
  • 在线拍卖:你可以知道在拍卖中出价的人确实发出了那个出价。
  • 安全通信:如果你收到一条终止连接的消息或一条可能导致你终止连接的坏消息,你可以知道该消息确实来自另一端,而不是有人试图关闭你的连接。

一般来说,在安全领域,完整性通常排在首位。有很多情况你需要完整性,但保密性不那么重要。然而,你很少需要保密性而不需要完整性。


两大完整性原语

上一节我们了解了完整性的应用,本节中我们来认识实现完整性的两大核心工具。

密码学哈希函数和消息认证码是两种主要的完整性原语。

  • 密码学哈希函数:让你安全地确定数据未被修改。任何人都可以生成密码学哈希,它不需要密钥。它是一个具有特殊属性的哈希函数。
  • 消息认证码:是验证数据未被修改的第二种方式。它们具有密码学哈希函数的所有完整性属性,但还有一个额外属性:它们确保生成MAC的人拥有密钥。只有拥有相同密钥的其他人才能检查MAC是否正确。

密码学哈希函数对于存储数据很有用。你可以确信没有人篡改过数据,并且由于不需要密钥,任何人都可以检查数据是否被篡改。

消息认证码在网络中很有用。如果你发送一条附加了MAC的消息,接收方如果拥有对应的密钥,就可以检查他们收到的消息是否是你发送的、未经篡改的消息,并且由于你必须拥有密钥才能生成MAC,这也提供了身份认证,因此得名“消息认证码”。


密码学哈希函数详解 🔍

现在,让我们首先深入了解密码学哈希函数。密码学哈希函数是一种具有特殊属性的哈希函数。

像普通哈希函数一样,密码学哈希函数从任意长度的输入产生固定长度的输出。例如,我可以从1GB的数据计算出一个256位的哈希值。它们的计算速度通常非常快,比网络传输还快。

密码学哈希函数,像普通哈希函数一样,通常通过对数据执行单次扫描,并基于每个字节或字执行一些数学运算来工作。这样,你就不必一次性将整个数据保存在内存中,可以流式处理。

密码学哈希函数提供了一个特性:抗碰撞性

这意味着,如果我有一段数据 X 和它的哈希值 H(X),那么要生成另一条消息 Y,使得 H(Y) = H(X),在计算上是不可行的。

当然,这样的碰撞是存在的。假设我有一个256位的密码学哈希,它有 2^256 个不同的可能取值。假设我正在哈希1GB的数据,那么有 2(230) 个不同的数据块,但只有 2^256 个不同的哈希值。虽然碰撞存在,但找到它们非常困难,以至于人们花费数年时间尝试也找不到。你不能仅仅尝试 2^1002^120 个不同的数据块。

这是一个非常深刻的概念。请确保你理解它:给定一个哈希值 H,要生成一段具有该哈希值的数据在计算上是不可行的。这看似简单,但功能强大。

核心公式/概念

  • 抗碰撞性:给定 H(X),找到 Y ≠ X 使得 H(Y) = H(X) 是计算上不可行的。

如何选择哈希函数

如果你需要使用哈希函数,那么请使用 SHA-256SHA-512。这些是SHA-2安全哈希算法,分别提供256位或512位哈希值。

SHA-1在今天几乎已被攻破。还有 SHA-3,它由美国国家标准与技术研究所在2012年10月选定,作为SHA-2的替代哈希算法,强度相同但基于不同的数学原理。这样,如果SHA-2出现问题,我们可以回退到SHA-3。

SHA-2由美国国家安全局设计并于2001年发布。考虑到最*关于NSA试图构建后门的新闻报道,你可能会认为SHA-2有后门。实际上很可能没有。它已经存在了十多年,并经过了公开审查。任何密码学和安全性领域的人士都研究过它,它看起来是安全的。破解SHA-2的难度堪比在物理学中发展出爱因斯坦的相对论。

SHA-3是由一组安全研究人员设计的,并在NIST赞助的新SHA-3竞赛中获胜。


哈希函数的应用:数据完整性校验

密码学哈希函数有一个很好的特性:一个小的哈希值可以唯一地描述一大段数据。

基本方法如下:

  1. 获取你的文件并计算其哈希值,存储为 H1
  2. 稍后,再次计算该文件的哈希值,称这个哈希值为 H2
  3. 如果新值与旧值不匹配,则文件中的某些内容已更改。
  4. 如果两者相等,那么你知道文件没有被篡改,因为没有人能生成一个具有相同哈希值的新文件或修改现有文件。

因此,你有时在下载软件时会看到发布者同时公布软件的哈希值。然后,你可以检查下载的内容是否是他们生产的,以确保在软件发布后没有人向分发包中插入恶意软件。


进阶应用:默克尔哈希树

哈希函数本身只能告诉你数据是否被修改。如果我有一个巨大的文件,我可以知道它被修改了,但不知道是哪里被修改。

如果你构建一个“默克尔哈希树”,你就可以知道文件的哪部分被修改了。

  1. 你对文件的小块进行哈希。
  2. 然后像这里展示的那样,创建一个哈希树。
  3. 如果顶部的哈希值不同,那么你就知道两个文件不同。
  4. 然后,你可以在对数级步数内遍历树,找出文件的哪部分不同。

这样,如果有人篡改了文件,你可以判断是因为意外截断,还是因为插入了恶意代码。

核心概念默克尔树 通过对数据块分层哈希,实现对大数据集的高效、局部完整性验证。


消息认证码详解 🔑

上一节我们介绍了无需密钥的完整性校验,本节中我们来看看如何结合密钥,实现同时保证完整性和认证的消息认证码。

密码学哈希函数非常有用,它们能告诉你数据是否被修改,但它们不需要秘密。任何人都可以生成和检查密码学哈希。而消息认证码则希望同时提供真实性。你想确保生成MAC的程序拥有一个秘密。

一旦我们有了密码学哈希函数,构建消息认证码就很容易了。我们需要做的就是将秘密与哈希结合起来。

我们可以定义一个消息认证码算法 HMAC,它接收一个密钥 K 和一条消息 M。它所做的就是将密钥前置到消息前,并对该数据计算哈希。然后,你可以只发送消息和MAC。为了检查消息认证码,接收方将密钥前置并计算MAC。他们知道只有拥有密钥的人才能产生这个MAC。

听起来很简单。我们有了一个密码学上强大的MAC。

错误

回想一下,哈希函数是通过迭代处理数据来工作的。对于大多数哈希函数,这意味着你将新数据合并到现有的哈希值中。换句话说,哈希值是计算的中间状态。

这意味着,如果我看到一条具有特定MAC的消息 M,我可以向 M 追加一些数据,形成 M‘,并计算出 M’ 的MAC。因此,正如安全领域常见的那样,简单的方法行不通,并且存在漏洞。我们需要更聪明的方法。

幸运的是,这个更聪明的方法并不复杂得多。


正确的MAC计算方法

以下是计算消息认证码的正确方法:

  1. 取你的密钥 K,与一个内填充(例如,重复64次的 0x36)进行异或操作,得到内密钥 K_i
  2. 计算 K_i 前置到消息 M 后的哈希值,得到内哈希 H_i
  3. 然后,通过将 K 与一个不同的外填充(例如,重复64次的 0x5C)进行异或操作,计算外密钥 K_o
  4. 计算 K_o 前置到内哈希 H_i 后的哈希值,结果即为最终的MAC。

为什么之前的攻击无效?
假设攻击者向 M 附加了一些信息。他们不知道 K。然而,MAC是由 M 的哈希值构成的,而不是 M 本身。因此,向 M 追加数据将导致完全不同的哈希值。之前方法中泄露的计算中间状态,通过这个内哈希被隐藏了起来。

核心公式/代码描述
HMAC(K, M) = H( (K ⊕ opad) || H( (K ⊕ ipad) || M ) )
其中 H 是哈希函数(如SHA-256),|| 表示连接,opadipad 是固定的填充常量。

这就是当今通常计算MAC的方式:对密钥和消息的一种变换进行密码学哈希,再对该哈希值和密钥的另一种变换进行密码学哈希。


结合保密性与完整性

最后一个问题。假设你同时需要保密性和完整性。你应该加密MAC,还是对加密后的数据计算MAC?

答案是后者:对加密后的数据计算MAC

在某些情况下,加密MAC并不总是安全的。因此,始终对加密后的数据计算MAC。


总结

在本节课中,我们一起学习了:

  1. 完整性的定义与重要性:确保数据来自可信来源且未被篡改,是安全系统的基础属性,通常比保密性更优先。
  2. 两大核心原语
    • 密码学哈希函数(如SHA-256):提供抗碰撞性,用于验证数据完整性,无需密钥。
    • 消息认证码(如HMAC):在哈希函数基础上结合密钥,同时提供完整性校验和身份认证。
  3. 关键应用:包括软件分发验证(哈希校验)、安全通信(MAC)、数据结构完整性(默克尔树)等。
  4. 重要实践:当同时使用加密和完整性保护时,应采用“先加密,后MAC”的模式。

记住,一个健壮的安全方案往往需要同时考虑保密性、完整性和可用性。完整性是连接信任与数据的桥梁。

课程 P128:公钥密码学 🔐

在本节课中,我们将要学习公钥密码学的基本原理。公钥密码学是现代大多数安全系统的核心组成部分。我们将了解它与对称密码学的区别、其工作原理、主要算法以及实际应用中的优缺点。


概述

公钥密码学与对称密码学不同,它使用一对密钥:一个可以公开的公钥和一个必须保密的私钥。公钥可以自由分发,而私钥则由所有者秘密保存。这种机制使得无需预先共享密钥即可实现安全通信和数据完整性验证。


公钥密码学如何工作?🔑

与对称密码学类似,公钥密码系统也包含三个核心算法:密钥生成加密解密

两者的主要区别在于两点。首先,密钥生成算法会生成两个密钥:一个公钥 K 和一个私钥 K⁻¹。加密时,使用公钥和明文来生成密文。解密时,则使用私钥和密文来恢复明文。

因此,如果你生成了密钥对,就可以自由分发公钥(这也是它名称的由来),并且确信只有拥有对应私钥的人才能解密用该公钥加密的信息。

然而,由于公钥会被重复使用多次,这意味着加密过程必须引入随机化。否则,发送相同明文的两方会产生相同的密文。如果处理的是短消息,攻击者就可能通过穷举所有可能的消息来破解。

例如,可以在加密前添加一些随机数据来生成密文。

这听起来很神奇:你可以生成两个密钥,一个公开,一个私有。拥有公钥的人可以发送数据,而只有拥有私钥的人才能解密。如果通信双方都拥有对方的公钥,那么我们似乎就不再需要对称密码学了。但实际情况并非完全如此,稍后我会解释原因。


公钥密码学与完整性:数字签名 ✍️

公钥密码学同样可以用于确保数据完整性,这通过一种称为数字签名的机制实现。

同样,它包含三个函数:生成(生成密钥对)、签名(使用私钥)和验证(使用公钥)。

签名像 MAC(消息认证码)一样提供完整性保证。没有私钥就无法为消息 M 生成有效的签名,但任何人都可以使用公钥来验证签名。此外,无法从私钥推导出公钥。


主要公钥算法 📊

目前存在多种公钥算法。用于加密的算法有 RSARabinElGamal。用于签名的算法有 RSARabinElGamalDSA

但公钥算法的工作原理与对称算法截然不同。以 RSA 为例,其基本思想非常简单:对大整数进行模幂运算。然而,将消息简单地转换为数字并进行变换并不一定是安全的,因此在使用时必须非常小心。我之前举过一个必须添加随机性的例子。

一般来说,最好使用经过测试的现有算法实现,而不是尝试自己重新实现。或者,你可以重新实现,但不要将其用于安全系统。对于许多此类算法,我们可以使用同一个密钥对进行加密和签名。尽管它们使用相同的密钥,但使用的算法却大不相同。例如,你不能通过用私钥加密文档来对其进行签名。


RSA 算法浅析 🧮

我不会深入所有细节,但我想让你了解一下其中一种非常著名的算法——RSA——是如何工作的。RSA 以其共同创造者 Rivest、Shamir 和 Adleman 的名字命名,他们为此获得了计算机领域的最高奖项——图灵奖。我介绍 RSA 是因为它在概念上非常简单。

以下是 RSA 密钥生成和加解密的核心步骤:

  1. 密钥生成:选择两个不同的、非常大的质数 PQ。计算它们的乘积 N = P * Q。然后利用 PQ 推导出公钥 K 和私钥 K⁻¹。将 NK 作为公钥公布。
  2. 加密:将消息 M 视为一个大数,计算 C ≡ M^K (mod N),得到的 C 即为密文。
  3. 解密:将密文 C 视为一个大数,计算 M ≡ C^{K⁻¹} (mod N),即可恢复出原始明文 M

私钥 K⁻¹ 是从 PQ 推导出来的。如果攻击者知道了 PQ,他们就能生成私钥并破解系统。而从 K 无法推导出 PQ

同样,从 N 也无法推导出 PQN 是两个质数的乘积,将 N 分解为 PQ 在计算上是困难的。如果有人找到了快速分解的方法,那么整个 RSA 体系就会崩溃。可以想象,许多人投入了大量精力来研究分解两个质数乘积的确切难度。

对于那些了解计算复杂性的人来说,我们知道这个问题属于 NP 计算类。它被怀疑不属于 P 类,但也被怀疑不是 NP 完全问题。这意味着我们最好的猜测是,你无法在多项式时间内解决它,但它也不像旅行商问题那样是 NP 中最难的问题。


公钥密码学的瓶颈与混合方案 ⚡

公钥密码学看起来非常神奇。你可以生成两个密钥,公开分发其中一个,然后实现机密性、完整性和真实性。那么我们为什么还要使用对称密码学呢?这其中当然有一个“陷阱”。

公钥密码学的计算速度比对称密码慢得多。

对称密码可以达到千兆比特每秒的速率。而公钥系统的执行时间则在毫秒级别。例如,使用 2048 位密钥运行 RSA 解密一条消息需要* 6 毫秒。

请记住,拥有私钥的一方负责解密。因此,如果你将公钥广泛分发,让许多其他方都能与你通信,那么你自身就会成为处理消息数量的瓶颈。

这就是为什么混合方案在今天非常流行。

其核心思想是:首先使用公钥密码学来加密一个对称密钥。

或者,用它来交换一些信息(一个秘密的会话密钥),然后用这个会话密钥来生成对称密钥。你使用公钥密码学来引导安全会话并交换一个秘密,然后利用这个秘密进行效率高得多的对称密码学操作。如果你想看一个详细的例子,我将在关于 TLS 的视频中介绍。


使用公钥密码学的注意事项 ⚠️

人们在使用公钥密码学时容易陷入的一个大陷阱是:对未充分指定的消息进行签名。

例如,如果我签署一条消息,我应该在消息中指定接收者是谁并给出有效期。否则,有人就可以简单地重放这条消息。由于我的公钥不会经常更改,只要人们还在使用我的公钥,签名消息就“有效”。这里的“有效”指的是它能通过验证函数。

因此,你需要在应用层面限制其使用。否则,一条写着“可以访问此文件”的签名消息可能会被攻击者获取并利用。相反,你应该签署类似“Nick 可以在万圣节中午之前访问此文件”这样的消息。


总结

本节课中,我们一起学习了公钥密码学的基础知识。我们了解了公钥和私钥的概念、它与对称密码学的区别,以及如何用于加密和数字签名。我们简要探讨了 RSA 算法的工作原理,并认识到公钥密码学虽然功能强大,但计算开销较大,因此在实际中常与对称密码学结合形成混合加密方案。最后,我们指出了在使用数字签名时需要注意消息规范,以防止重放攻击。

课程 P129:证书 🔐

在本节课中,我们将要学习一个当今非常普遍且至关重要的安全原语——证书。每当你建立 SSH 或 HTTPS 会话时,都会用到它。我们将了解证书如何解决公钥分发中的信任问题,以及它们如何构成现代网络安全通信的基础。

公钥分发的挑战 🔑

上一节我们介绍了公钥密码学,它允许我们验证持有与公钥关联的私钥的人签署了某个文档。

但这里存在一个关键问题:我们如何知道正确的公钥是什么?我们如何知道 www.ebay.com 拥有哪个公钥?

答案是使用证书。假设我们想与一个服务器(例如 www.amazon.com)进行安全通信。如果我知道 www.amazon.com 的公钥,那么我就可以使用公钥密码学与该服务器安全通信,并验证它确实拥有与我所用公钥关联的私钥。我们还可以使用公钥加密来交换对称密钥。

然而,这里缺少了一个步骤:我如何获取服务器的公钥?是从网页上找到的吗?如果我从不安全或随机的来源获取它,我如何确定这真的是该服务器的公钥,而不是一个冒充该服务器的攻击者的公钥?

中间人攻击的威胁 🕵️

上一节我们提到了信任问题,本节中我们来看看一个具体的威胁场景。

例如,想象一个非常简单的攻击。我想与一个服务器通信,所以我向它请求其公钥。它给了我一个密钥,然后我可以验证它是否拥有关联的私钥。但这完全对中间人攻击开放。

攻击者可以冒充服务器,并给我它自己的公钥。我无法分辨哪个密钥是正确的。攻击者看起来就像服务器,只是它拥有一个不同的密钥。然后,攻击者可以打开一个到真实服务器的连接,并冒充你。由于你正在与攻击者通信,它能看到你发送的一切,并将其转发给真实服务器。它可以重写、拦截你发送的任何信息,甚至注入新的流量,例如密码等敏感数据。

因此,你需要一种方式,能够接收 www.amazon.com 的公钥,并有理由确信它确实是 www.amazon.com 的。在理想情况下,最好有一个我信任的人告诉我 www.amazon.com 的密钥是什么。这正是证书的作用。

证书:建立信任链 📜

上一节我们看到了中间人攻击的风险,本节中我们来了解证书如何解决这个问题。

抽象地说,证书是一个数字文档(本质上是一串字节),它将一个名称绑定到一个值(通常是公钥)。这个文档由一个私钥(记作 K1_inverse)签名。

如果我已拥有对应的公钥 K1,那么我就可以验证这个文档确实是由正确的私钥签名的。如果我信任持有 K1_inverse 私钥的一方,那么我就可以信任他们的声明:某个名称(例如主机名)拥有公钥 K2。这样,在与该名称通信时,我就可以使用 K2

通过这种方式,我建立了一条信任链。如果我从一个我信任的方的公钥开始,那么这个方可以给我其他方的公钥,而这些方又可以给我更多方的公钥。

证书错误与配置问题 ⚠️

如果你经常浏览网页,可能多次看到过类似这样的错误信息(以 Firefox 为例)。它告诉你无法信任该站点的安全性。

通常,你看到这个错误是因为证书存在问题。例如,我在斯坦福的研究小组运行着 sing.stanford.edu 服务器,它还有其他几个别名,如 tinywes.stanford.edu。斯坦福为我提供了一个证书,声明这些名称与服务器的公钥关联。但如果我向斯坦福的 DNS 添加了一个新名称(例如 bad.stanford.edu),那么这个证书就不会包含该名称。如果你尝试通过 HTTPS 连接到 bad.stanford.edu,就会收到这样的错误,因为斯坦福给我的证书没有覆盖那个名称。

因此,你经常会在以下情况遇到此错误:

  • 主机有别名,但证书未包含。
  • 证书是为旧名称颁发的,而名称已更新。

当然,这也可能是一个攻击者在运行不同的服务器,并试图让你相信它是可信的。一般来说,看到这个错误意味着有人在安全配置上出现了失误。鉴于安全的微妙性和复杂性,即使这可能只是一个小错误,看到此类错误时也应保持警惕,不要轻易信任该服务器。

根证书与信任锚 🏛️

上一节我们讨论了证书错误,本节中我们来看看信任体系是如何实际运作的。

当今的运作方式是,每个人都信任少数几个签名机构(证书颁发机构,CA),并知道它们的公钥。这些公钥被硬编码到你的浏览器或操作系统中。这也是检查程序完整性的一个重要原因。

以下是我 Mac 上安装的密钥示例(通过“应用程序”->“实用工具”->“钥匙串访问”查看)。你可以看到许多预先安装的不同密钥。这些都是根密钥,它们的公钥已被硬编码到操作系统中,因此是我可以信任的。例如,这里有 VeriSign 和 Apple 等根机构。

这些根机构可以为其他方签署密钥。例如,当我通过 HTTPS 访问 Google 时,可以看到 www.google.com 的证书是由“Google Internet Authority”签署的,而后者又由“Geotrust Global Certificate Authority”签署。这就是证书的层级结构。

签名机构通常被称为 CA。但需要认识到,证书所声明的全部内容就是:某人证明某个主机拥有这个密钥。如果证书链中的任何一方是攻击者,那么你可能会被欺骗。

证书的类型与总结 📝

由于上述信任链的风险,实际上存在许多不同类型的证书。有些证书(例如我用于 sing.stanford.edu 的证书)只需要填写一个网页表格即可获得。而其他证书则需要纸质文件验证,甚至可能需要当面会晤。

这就是当今 TLS/SSL(当你看到浏览器地址栏上的锁形图标时)的工作原理:

  1. 你连接到一个服务器。
  2. 服务器提供一个包含其公钥的证书。
  3. 如果该证书链终结于一个你信任的根证书颁发机构(即你已经拥有其公钥并能验证其签名),那么你就信任证书中的密钥,并可以开始与服务器进行加密通信。

关于 TLS 的具体细节,我们将在后续视频中详细解释。


本节课中我们一起学习了:

  • 证书 的核心作用:将一个名称(如域名)绑定到一个公钥,并由可信方签名,从而解决公钥分发中的信任问题。
  • 面临的挑战:中间人攻击如何利用公钥分发的不确定性。
  • 信任链 的建立:从硬编码在系统中的根证书(CA 公钥)开始,逐级验证和信任。
  • 常见的证书错误 及其含义,提醒我们注意安全配置。
  • 现代网络(HTTPS)中证书的实际应用 流程。

证书是构建安全网络通信(如 HTTPS、SSH)的基石,它通过数字签名和预先建立的信任关系,确保我们是在与正确的对方进行通信。

计算机网络课程 P13:IPv4地址详解 🌐

在本节课中,我们将要学习互联网协议版本四(IPv4)地址。我们将了解IPv4地址的格式、作用,以及如何通过子网掩码来划分网络。这是理解网络设备如何相互通信的基础。


互联网协议允许两台计算机在一个构建起来的网络上交换消息。这个协议运行在许多不同的链路层之上。它通过地址来实现设备间的通信。一个IP数据包包含一个源地址和一个目的地址。路由器根据数据包的目的地地址,决定将其转发到哪个链接。

基于数据包目的地地址的转发,是IP路由的核心。让我们详细看看IP版本四地址的格式。

IPv4地址的格式与目标 🎯

IPv4地址的原始目标是将许多不同的网络连接在一起。这需要协议具备一种方式,以便引用不在其本地网络上的计算机,并且确保地址是唯一的。例如,一个在IBM网络上的计算机,和一个通过串行线连接到路由器的计算机可以相互交谈。为了实现这一点,IPv4地址被设计出来。

一个IPv4地址是32比特长。这32比特通常被写成四个八位组,也就是四个以点分十进制形式表示的数值,格式为 A.B.C.D

以下是三个IPv4地址的例子:

  • 1.71.64.64
  • 64.1.2.8
  • 30.70.6.80.2.12 (注:此地址格式有误,标准IPv4地址应为4组数字)

通过IP连接的所有设备都必须有一个IPv4地址。IP层会将目的地地址为此地址的数据包交付给对应的那个设备。

子网掩码的作用 🔍

除了IP地址之外,一个网络设备通常还配有一个被称为子网掩码的东西。子网掩码用于区分哪些IP地址在本地网络中,哪些地址需要通过IP路由器转发。

例如,想象一台笔记本电脑连接在一个无线网络中。为了将数据包发送到同一个无线网络中的其他设备,数据不需要经过IP路由器。理论上,你可以直接将数据包发送到目标设备,因为它们处于同一个网络中。

子网掩码被写成一连串的1,从最高有效位开始,后面跟着一连串的0。一个常见的子网掩码 255.255.255.0 意味着前三个八位组(共24位)都是网络部分。

具体来说:

  • 子网掩码 255.255.255.0 意味着网络部分是24位长。
  • 子网掩码 255.255.255.128 意味着网络部分是25位长。
  • 子网掩码 255.255.0.0 意味着网络部分是16位长。

你可以通过将设备的IP地址和它的子网掩码进行按位与运算,来确定两台计算机是否在同一网络。如果运算后得到的网络地址相等,则它们处于同一网络。

判断是否在同一网络的公式:
(IP地址1 & 子网掩码) == (IP地址2 & 子网掩码)

实践查看:我的电脑网络配置 💻

让我们看看在实际的电脑上如何查看这些信息。我打开终端并使用 ifconfig 程序。我的电脑通过Wi-Fi连接到互联网,这个网络接口正好名为 en0

如果我们查看关于 en0 的信息,可以看到:

  • 我的IPv4地址是 192.168.1.106
  • 我的子网掩码是 0xffffff00,这是十六进制表示法,相当于 255.255.255.0

这意味着,如果我需要向以 192.168.1. 开头的地址发送IP数据包(例如 192.168.1.50),我应该尝试直接发送(因为它们在同一个局域网内)。但如果目的地址不是以 192.168.1. 开头(例如 8.8.8.8),那么数据包就需要被发送到默认网关(路由器),由路由器负责将其转发到外部网络。


本节课中我们一起学习了IPv4地址。我们了解了IPv4地址是一个32位的唯一标识符,通常以点分十进制表示。我们还深入探讨了子网掩码的核心作用,它像一把尺子,划定了本地网络的边界,帮助设备判断一个目标地址是在本地直接通信,还是需要交给路由器进行转发。理解IP地址和子网掩码是掌握网络基础通信原理的关键一步。

课程 P130:传输层安全 (TLS) 详解 🛡️

在本节课中,我们将要学习传输层安全 (TLS) 的核心概念和工作原理。TLS 是 HTTPS 协议的基础,为网络通信提供机密性、完整性和真实性保障。

TLS 概述

传输层安全正如其名,它在传输层为应用程序之间的通信提供安全保障。TLS 是位于 TCP 之上的会话层协议。

它提供了类似 TCP 的流抽象。因此,对于大多数应用程序而言,TLS 看起来就像一个双向的、可靠的字节流。但 TLS 为这个流增加了机密性完整性真实性

正确使用 TLS 可以保护通信免受窃听、篡改和欺骗攻击。TLS 的最新版本是 1.2 版,由 RFC 5246 定义。TLS 最初由网景公司开发,名为安全套接字层 (SSL)。其版本演进顺序为:SSL 2.0、SSL 3.0、TLS 1.0、TLS 1.1,以及现在的 TLS 1.2。HTTPS 协议正是基于 TLS。

TLS 使用的密码套件与密钥

TLS 支持多种可用的密码套件。在建立 TLS 会话的过程中,客户端和服务器需要协商四种独立的密码套件。

以下是协商的四种密码套件:

  1. 用于服务器认证的密码套件(也可选用于客户端认证)。
  2. 用于交换对称密钥的密码套件。
  3. 用于对称机密性的密码套件。
  4. 用于对称完整性的密码套件。

这些套件通过一个五步的会话启动协议进行协商。这一切都发生在 TCP 连接建立之后,因此这些消息是通过 TCP 发送的。

TLS 会话建立过程

上一节我们介绍了 TLS 使用的密码套件,本节中我们来看看它们是如何通过握手协议协商并建立安全连接的。

以下是 TLS 会话建立的五个步骤:

  1. 客户端问候:客户端发送其支持的密码套件列表和一个它生成的随机数。此步骤以明文发送。
  2. 服务器问候:服务器响应选定的密码套件、它自己的随机数以及包含其公钥的证书。此步骤也以明文发送。
  3. 预主密钥交换:客户端将所谓的“预主密钥”用服务器的公钥加密后发送给服务器。客户端和服务器使用这个预主密钥以及之前明文交换的两个随机数,计算出会话所需的密钥。
  4. 客户端完成:客户端发送一个“完成”消息,该消息使用从服务器随机数、客户端随机数和预主密钥生成的对称密钥进行加密和认证。此消息包含握手消息的消息认证码 (MAC),以确保双方看到的消息一致。
  5. 服务器完成:服务器发送一个“完成”消息,其安全保护方式与客户端的完成消息类似,同样包含握手消息的 MAC。

对握手消息进行 MAC 计算,使得 TLS 能够抵御试图迫使双方选择不同密码套件的攻击者。由于前两个步骤未受保护,既无机密性也无完整性,攻击者可能进行中间人攻击以尝试更改提议和选定的密码套件。对握手消息进行 MAC 计算可以让双方检测到此类攻击。至此,双方已建立一个使用协商好的对称密码套件保护的安全连接。

TLS 记录协议

在建立了安全连接之后,TLS 需要处理应用层数据。为了提供完整性,TLS 需要将应用数据分割成可以附加消息认证码的数据块。

TLS 将应用数据流分割成记录。记录中包含数据长度和 MAC。这些记录使用选定的密码套件和密钥进行加密,然后通过 TCP 发送。在 TCP 层,这些数据表现为数据流,TCP 再将其分割成段。

记录可能远大于 TCP 段,因此单个记录可能被分割成多个段,记录边界和段边界可能不对齐。

TLS 的特性之一包括压缩。例如,如果配置 TLS 仅提供完整性而不提供机密性,那么发送的就是明文。这些文本通常可压缩性很高,压缩比可达* 10:1。因此可以配置 TLS 对数据进行压缩。请注意,如果启用了机密性,压缩仍然有益,因为加密后的比特流应呈现随机性。

会话密钥的生成

现在,让我们深入了解 TLS 如何建立其会话密钥。请记住,服务器和客户端都提供了随机数。这样,即使其中一方的随机数生成器不够好,最终结果仍然具有随机性。

客户端还发送了一个用服务器公钥加密的预主密钥。客户端和服务器结合这三部分信息,生成一个主密钥,然后从主密钥派生出会话密钥。

一旦计算出主密钥,客户端和服务器就会丢弃预主密钥。它们生成六个密钥,其长度由所使用的密码套件决定。

以下是生成的六种密钥:

  • 用于加密客户端到服务器数据的密钥。
  • 用于对客户端到服务器数据进行 MAC 计算的密钥。
  • 用于加密服务器到客户端数据的密钥。
  • 用于对服务器到客户端数据进行 MAC 计算的密钥。
  • 客户端初始化向量(适用于需要它的密码)。
  • 服务器初始化向量(适用于需要它的密码)。

拥有这个主密钥后,客户端和服务器可以通过选择新的随机数来重新生成新密钥。这意味着可以使用相同的主密钥恢复会话,但使用新的密钥。

密钥生成过程详解

上一节我们列出了生成的密钥类型,本节我们具体看看它们是如何从随机数中计算出来的。

整个过程如下图所示。客户端和服务器将客户端随机数、服务器随机数和预主密钥作为输入,传递给一个称为伪随机函数 的组件,该函数生成看似随机的比特流。这产生了 48 字节的随机比特,即主密钥。

TLS 将主密钥和两个随机值作为伪随机函数的输入,生成所有密钥所需的比特数。例如,如果 MAC 密钥是两个 512 位,加密密钥是两个 56 位,初始化向量是两个 128 位,那么就需要调用伪随机函数生成足够多的次数,以产生总计 1792 位的密钥材料。

密钥生成的核心公式可以概括为:

主密钥 = PRF(预主密钥, “主密钥”, 客户端随机数 + 服务器随机数)[0..47]
密钥块 = PRF(主密钥, “密钥扩展”, 服务器随机数 + 客户端随机数)

然后从密钥块中按顺序提取出所需长度的客户端 MAC 密钥、服务器 MAC 密钥、客户端加密密钥、服务器加密密钥等。

总结

本节课中我们一起学习了传输层安全 (TLS) 协议。我们了解了 TLS 如何通过在 TCP 之上建立安全会话,为应用数据流提供机密性、完整性和真实性。我们详细探讨了 TLS 握手协议,包括密码套件协商、基于随机数和预主密钥的密钥交换过程,以及用于验证握手完整性的 MAC 机制。此外,我们还学习了 TLS 记录协议如何封装数据,以及会话密钥是如何从主密钥派生出来的。掌握这些原理,是理解现代网络安全通信(如 HTTPS)的基础。

课程 P131:TLS 随机值与密钥生成 🔐

在本节课中,我们将学习 TLS 协议中随机值的构成,以及攻击者需要尝试多少次才能破解会话密钥。我们将分析客户端随机数、服务器随机数和预主密钥的字节长度,并计算在最坏情况下攻击者所需的尝试次数。


TLS 随机值的构成

上一节我们介绍了 TLS 握手的基本流程,本节中我们来看看 TLS 协议中使用的几个关键随机值。

TLS 随机值的长度为 32 字节。

以下是其具体结构:

  • 前 4 字节是一个时间戳。
  • 后 28 字节是随机数。

预主密钥的长度为 48 字节。

以下是其具体结构:

  • 前 2 字节是协议版本号。
  • 后 46 字节是随机数。


密钥的生成与攻击场景

假设你的 TLS 会话使用上述随机值来生成 1024 字节的密钥。

那么,攻击者为了破解这些会话密钥,在最坏情况下(即穷举攻击)可能需要尝试的最大次数是多少?

我们假设攻击者能够根据输入正确计算出伪随机函数的输出。这意味着:

  • 攻击者可以看到客户端和服务器随机值。
  • 攻击者看不到预主密钥。
  • 攻击者可以计算伪随机函数。

请以 2 的指数形式写出你的答案。例如,如果需要尝试 2^31 次,则写 31。


计算攻击尝试次数

根据以上信息,攻击者不知道的是预主密钥中那 46 字节的随机部分。因此,攻击者需要穷举所有可能的预主密钥。

预主密钥的随机部分长度为 46 字节。每字节有 256 种可能(2^8),因此总共有:
(2^8)^46 = 2^(8*46) = 2^368 种可能性。

所以,攻击者最多需要尝试 2^368 次。答案应写为 368


总结

本节课中我们一起学习了 TLS 协议中随机值的结构,包括 32 字节的客户端/服务器随机数和 48 字节的预主密钥。我们分析了在最坏情况下,攻击者要破解由这些随机数生成的会话密钥,需要尝试的最大次数为 2^368 次,这体现了 TLS 协议通过足够长的随机数来保证密钥安全性的设计思想。

课程 P132:TLS 握手协议中的密钥交换与安全性 🔐

在本节课中,我们将学习 TLS 握手协议中密钥交换的核心机制,特别是预主密钥的作用及其安全性。我们将了解攻击者可能面临的挑战,以及为什么一个看似简单的秘密值能提供强大的安全保障。


上一节我们介绍了 TLS 握手的基本流程,本节中我们来看看握手过程中交换的随机值与最终密钥生成的关系。

握手过程中交换的两个随机值(客户端随机数和服务器随机数)对攻击者是已知的,因为它们以明文形式发送。


真正的秘密是预主密钥,其长度为 46 字节(即 368 比特)。

如果攻击者能够猜中这个值,那么它就可以利用伪随机函数,结合已知的两个随机值,重新计算出主密钥。

伪随机函数(PRF)的公式可以表示为:
master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)


获得主密钥后,攻击者就能进一步计算出用于加密和完整性验证的会话密钥。

然而,猜中一个 368 比特长的预主密钥需要尝试的次数是 2 的 368 次方,这是一个极其巨大的数字。


以下是关于此安全机制的关键点总结:

  • 已知信息:客户端与服务器的随机数在握手时明文传输,对攻击者可见。
  • 核心秘密:预主密钥是真正的秘密,长度为 46 字节(368 比特)。
  • 密钥派生:主密钥由预主密钥、两个随机数通过伪随机函数(PRF)计算得出。
  • 安全性基础:攻击者若想破解,必须暴力猜测预主密钥。2^368 次尝试在计算上是不可行的,这构成了 TLS 协议安全性的基石。


本节课中我们一起学习了 TLS 握手协议中密钥交换的核心。我们明确了攻击者已知的信息(两个随机数)与真正的秘密(预主密钥)之间的区别,并理解了通过伪随机函数派生最终密钥的过程。最关键的是,我们认识到由于预主密钥的熵足够大(368 比特),对其进行暴力破解在计算上是不可行的,这正是 TLS 能够保护我们通信安全的关键所在。

课程 P133:分层架构与TLS的挑战 🔐

在本节课中,我们将探讨计算机网络中的分层设计原则,并分析这种设计如何与TLS(传输层安全)协议产生交互,特别是在虚拟主机场景下所面临的挑战。


分层架构概述 📊

现在,让我们稍微转换一下思路,实际看一看分层架构及其运作方式。

分层是计算机网络设计中一个普遍且重要的原则。你已经多次见过它的应用。

以下是分层架构的主要优势:

  • 关注点分离:每一层负责特定的功能。
  • 独立演进:各层可以独立地进行更新和改进。
  • 易于适应:能够更好地适应未来的新技术。

然而,分层设计有时也会带来阻碍。


TLS与虚拟主机的冲突 ⚠️

上一节我们介绍了分层架构的好处,本节中我们来看看它在实际应用中可能引发的问题。TLS如今被广泛用于通过HTTPS进行安全的网络交易。

但常见的情况是,一台网络服务器通过一种称为虚拟主机的技术来运行多个网站。所有网站的域名都映射到该服务器的同一个IP地址。

客户端通过端口443(HTTPS)连接到所有这些网站。直到HTTP请求到达时,网络服务器进程才知道该请求是针对哪个站点的。HTTP请求中的 Host 头部字段会告知服务器这一信息。

例如,如果你访问 sing.stanford.edutiny.us.stanford.edu,它们指向同一台服务器。服务器可以配置一个路径,根据请求中的主机头来提供不同的网页。

这种机制可能会破坏TLS,使其无法完全正常工作。原因是什么?

以下是几个可能被破坏的环节:

  • 它破坏了服务器身份验证吗?
  • 它破坏了密钥交换吗?
  • 它破坏了随机数生成吗?
  • 它破坏了握手消息的路由吗?
  • 它破坏了预主密钥的生成吗?

答案是:它破坏了服务器身份验证。


问题根源:跨层信息依赖 🔍

TLS握手和安全会话的建立发生在任何应用层数据交换之前。作为此交换的一部分,服务器需要提供一个证书,该证书将一个公钥绑定到一个名称。

但问题在于,在握手阶段,服务器不知道应该使用哪个名称。例如,我的服务器无法判断一个即将建立的连接是为了 tiny.us.stanford.edu 还是 sing.stanford.edu。因此,它不知道应该提供针对 tiny.us 还是 sing 的证书。

在我的案例中,我有一个同时包含这两个名称的证书。但如果我想在服务器上添加一个新的主机名,比如一个名为 www.networkingclass.com 的网站,那么TLS就会报错。

这里的核心问题在于:会话层(第5层)需要知道客户端试图联系的主机名。但这个名称只存在于应用层(第7层)。客户端已经将名称解析为IP地址,因此第3层只知道IP地址。

这个例子清晰地展示了分层封装功能如何可能导致冲突,并实际上成为一种阻碍。


总结 📝

本节课中我们一起学习了分层架构的设计优势与潜在局限。我们重点分析了在虚拟主机环境下,由于TLS握手需要的主机名信息(位于应用层)在建立安全连接时(发生在会话/传输层)尚不可用,从而导致服务器身份验证出现困难的经典案例。这揭示了严格分层设计在实际协议交互中可能面临的跨层信息依赖挑战。

课程 P134:网络安全与密码学基础 🛡️

在本节课中,我们将学习网络安全的基本概念以及密码学如何帮助我们构建安全的通信系统。课程将涵盖网络威胁模型、三大安全原则,以及实现这些原则的核心密码学工具。


网络威胁模型:假设网络由对手控制 🌐

上一节我们介绍了课程概述,本节中我们来看看网络安全的根本出发点:威胁模型。

网络并非你的朋友,它由对手控制。这意味着我们必须假设通信环境是充满敌意的。

以下是网络对手可能采取的具体攻击行为:

  • 窃听:对手可以监听你传输的任何数据。
  • 篡改:对手可以修改或重写你的消息。
  • 抑制:对手可以阻止你发送的消息到达目的地。
  • 欺骗:对手可以冒充他人,也可以冒充你。
  • 中间人攻击:对手可以拦截你的通信流量,然后再转发出去。
  • 劫持:对手可以在不同网络层劫持通信,例如:
    • 第二层通过以太网机制。
    • 第三层通过ICMP或其他协议。
    • 第四层通过向TCP流中注入新的数据段。

许多出于良好初衷设计的机制,在对手手中都可能变成强大的武器,用于窃取数据或拒绝网络服务。


三大安全原则:构建安全系统的基石 🔐

尽管威胁重重,但我们仍有希望。通过遵循三个基本的安全原则,我们可以在面对攻击时构建安全的系统。

1. 保密性

保密性让你能够进行秘密通信,即使他人可以读取你的消息。使用保密性,你可以在不受信任的网络上与另一方通信,并确信没有其他人能读懂你的流量。或者至少,对他人来说,解读你的流量在计算上是不可行的。

2. 完整性

完整性让你确信数据在传输途中未被篡改。你学习了密码学机制,可以让你以极低的成本验证一段数据是否被更改。

3. 真实性

通过真实性,你可以确信对方拥有一个秘密。这个秘密可以是你们事先共享的,也可以是对方能证明其拥有的。你当然无法完全确定对方的身份,但至少可以确信他拥有一个只有你信任的实体才有的秘密。


核心密码学工具 🧰

了解了安全原则后,我们来看看实现这些原则的具体工具。

对称加密

在对称加密中,通信双方共享一个秘密密钥。它主要用于实现保密性

核心公式密文 = 加密算法(明文, 密钥)明文 = 解密算法(密文, 密钥)

分组密码

分组密码将数据按固定大小的块进行转换。常见的模式包括:

  • 电子密码本模式:存在安全风险,相同的明文块会产生相同的密文块,容易暴露模式。
  • 密码分组链接模式:解决了ECB模式的问题,通过将前一个密文块与当前明文块混合,确保相同的明文块会产生不同的密文块。

密码学哈希函数

哈希函数具有易于计算,但攻击者难以生成一个能产生特定哈希值的输入的特性。这被称为抗碰撞性。它主要用于验证完整性

核心特性:给定输出 H(m),难以找到输入 m;难以找到两个不同的输入 m1m2,使得 H(m1) = H(m2)

消息认证码

MAC结合了密码学哈希和共享密钥,用于同时验证消息的完整性真实性。使用MAC,你可以确信消息未被篡改,且发送者拥有密钥。

警告:生成MAC的简单方法充满风险,应非常小心。


密钥分发与公钥密码学 🔑

如何安全地共享秘密密钥?这引出了另一种密码学系统:公钥密码学。

在公钥密码学中,每个实体有一对密钥:一个公钥和一个私钥。用公钥加密的信息只能用对应的私钥解密。这样,你可以自由分发公钥,任何人都能向你发送只有你能解密的加密数据。

公钥密码学也可用于生成类似MAC的机制,称为数字签名。签名只能用私钥创建,但可以用公钥验证。

证书与信任链

证书是建立信任链以获取公钥的一种方式。例如,如果你信任苹果公司,那么由苹果公司签署的、告知你他人公钥的文件,你就可以信任并使用那个公钥与之通信。

信任链模型你信任的根证书 -> 签署 -> 中间证书 -> 签署 -> 目标实体的证书


总结与最佳实践 ⚠️

本节课中我们一起学习了网络安全和密码学的基础知识。我试图让你了解这些重要机制的工作原理,其中包含大量细节。

然而,如果你要从本单元带走一个最重要的教训,那不应是分组密码具体如何工作,而应是:在安全领域,犯错非常容易

因此,请遵循以下最佳实践:

  • 不要尝试自己实现这些密码学机制。很容易忽略一个最终成为漏洞的细节。
  • 使用现有的、开源的密码系统实现
  • 使用经过长期检验和充分理解的方法
  • 始终保持谨慎,并遵循最佳实践

最后,请记住:对手可能正在监听

课程 P135:SIP 协议与网络安全 🎤🔒

在本节课中,我们将跟随 Jon Peterson 的访谈,了解互联网早期发展、SIP(会话发起协议)的诞生及其在当今网络中的应用,并深入探讨其安全模型面临的挑战与妥协。我们还将探讨互联网治理、标准制定过程以及未来可能影响网络格局的技术趋势。


早期经历与互联网治理

上一节我们介绍了课程背景,本节中我们来看看 Jon Peterson 是如何进入互联网治理领域的。

Jon Peterson 在 1990 年代末的互联网早期浪潮中,有幸身处其中。他当时在波士顿的一家初创公司工作,该公司后来被 Level 3 Communications 收购。这使他搬到了科罗拉多州的博尔德。Level 3 是互联网的一级骨干网提供商之一,深度参与了互联网工程任务组(IETF)等标准制定机构的工作。正是这个机会,让他得以与顶尖专家共事,并开始参加 IETF 会议。

他发现 IETF 是一个充满智慧、严谨求实的社区,其核心在于观点的“精英治理”。参与者不是代表公司,而是提出自己认为的最佳方案。一旦深入其中,就会自然地接触到其他相关领域,如 W3C(负责 Web 标准如 HTML)和 ICANN(负责域名分配),从而在技术与公共政策的交叉点展开工作。


SIP 协议的诞生与发展

上一节我们了解了 Jon 进入标准领域的历程,本节中我们来看看他早期工作的重点——SIP 协议。

在 1990 年代初期,互联网上并没有成熟的语音或视频通信服务。直到 1996-1997 年左右,计算能力、网络条件和计算机接口才达到一个“甜蜜点”,使得首批商用互联网语音服务成为可能。

Jon 当时的工作集中在“软交换”基础设施上。其核心思想是:用一台通用计算机(如 Unix 服务器)来承载传统电话交换机的控制*面逻辑。公式可以简单理解为:

软交换系统 = 通用服务器 + 电话控制*面软件

这颠覆了由北电、朗讯等公司生产的昂贵、专用、笨重的传统电话交换机市场。如今,软交换已成为主导范式。

一旦建立了软交换,这些设备需要通过互联网相互通信,以协调呼叫,而不是使用传统的、基于 X.25 的 SS7 信令系统。这时,像 SIP 这样的协议就登场了。

Jon 早期在 SIP 上的工作主要集中在“电话网络替代”上,即如何在不触碰传统网络的情况下,完全通过互联网建立呼叫。这使得软交换成为传统电话网络与互联网语音(VoIP)空间之间的桥梁,对于 Skype 等应用能够从电脑呼叫普通固定电话用户至关重要。


SIP 的安全模型与妥协

上一节我们探讨了 SIP 如何连接两个世界,本节中我们来看看其安全模型的设计与面临的现实挑战。

在制定 SIP 核心规范 RFC 3261 时,Jon 负责编写安全章节。起初计划只有一节,但最终扩展成了四个章节,成为他当时发布过的篇幅最大的 RFC。SIP 的安全问题一直是个“问题儿童”。

设计一个能保证端点间完整性和保密性的协议固然理想。但现实是,一旦有中间服务器参与(例如,为了支持一个号码绑定多个设备),这些服务器就需要访问信令和媒体流信息。为了 SIP 能被市场广泛采纳,在设计其安全模型时做出了许多必要的妥协。

Jon 坦言,如果当时在安全上做得更彻底,SIP 可能就不会取得今天的成功,因为它可能因过于复杂或难以部署而无法流行。*期关于大规模国家监控的 revelations,可能会催生政治意愿,改变未来协议设计中能达成的共识。


SIP 的广泛应用与根本权衡

上一节我们讨论了安全与实用的矛盾,本节中我们来看看 SIP 在哪些地方取得了成功。

SIP 的应用比大多数人意识到的更为广泛:

  • Skype:当使用 Skype 拨打或接听普通电话时,其内部协议通常会转换为 SIP,以便通过网关连接到电话网络。
  • 家庭电话服务:来自有线电视或电信运营商的 VoIP 或固定电话服务,后台很可能使用了 SIP。
  • 移动网络:3G/4G 网络内部也使用 SIP 信令。

然而,在这些网络(尤其是移动和有线网络)中使用的 SIP 版本,其架构更接*于传统电话网络,依赖网络元素来管理流量。这与互联网“将智能置于端点”的基本原则存在根本性的权衡。理想情况下,网络中间设备不应阻碍端点间直接协商(例如使用新的编解码器)。但为了替代具有百年历史、包含紧急呼叫等关键服务的电话网络,并满足其可靠性要求,做出妥协是不可避免的。


软交换与软件定义网络(SDN)的*行演进

上一节我们看到了 SIP 在现实中的权衡,本节中我们来看看历史技术变革与当今趋势的关联。

Jon 认为,早期的“软交换”革命(用通用服务器替代专用电话交换机)与今天的“软件定义网络”(SDN)趋势存在许多相似之处。不过,他认为情况可能不会完全重演,因为当今的路由器厂商(如思科、Juniper)比当年的传统电话交换机厂商更为敏捷。

例如,IETF 中正在讨论的 I2RS(路由系统接口)提案,就是一种让软件与路由器的转发信息库(FIB)交互的方式。路由器厂商正试图将其作为一种工具吸纳,在利用其优势的同时,不必然侵蚀其现有的市场控制力和庞大的安装基础。

核心路由器并不像旧式电话交换机那样严重阻碍网络创新,后者是推动软交换发展的另一个重要原因。尽管如此, parallels 确实存在,这对路由器业务构成了真实挑战。


当今 IETF 的前沿工作与展望

上一节我们回顾了历史与现在的联系,本节中我们来看看当前互联网标准领域有哪些值得关注的新动向。

对于想了解未来几年可能显著改变网络面貌的技术的人,Jon 建议关注以下 IETF 领域的进展:

  • I2RS:如前所述,关注软件如何更智能地参与路由决策。
  • Perpass:这是一个新成立的论坛,专门讨论 PRISM 事件引发的安全问题,并研究是否需要对 IETF 的标准制定流程进行结构性改革,以设立新的安全基准。

此外,Jon 个人还致力于以下两个他认为能产生重大影响的领域:

  1. 内容分发网络:研究 CDN 如何通告其服务覆盖范围和能力,以促进 CDN 间的协作或对等互联,从而更优化地选择 CDN,提升互联网流量效率,缓解视频流量增长带来的瓶颈。
  2. 电话网络与互联网的交叉问题:特别是应对来自互联网的“机器人骚扰电话”。他正在研究如何建立更好的身份服务,使得伪造来电更加困难,并更容易追溯通过互联网拨打电话的责任方。美国联邦贸易委员会(FTC)和联邦通信委员会(FCC)对此非常关注。

总结

本节课中,我们一起学习了 Jon Peterson 分享的互联网治理与标准制定历程。我们深入探讨了 SIP 协议如何从软交换的概念中诞生,成为连接传统电话网与互联网语音服务的关键桥梁,并理解了其安全模型在设计时面临的市场采纳与理想安全之间的根本权衡。最后,我们展望了当前 IETF 中像 I2RS、CDN 互联和反骚扰电话等可能塑造未来网络面貌的前沿工作。技术的发展总是在理想、现实与妥协中不断前行。

计算机网络基础 P136:TCP/IP 与网络架构演进 🖧

在本节课中,我们将跟随网络专家 Kevin Fall 的分享,了解 TCP/IP 协议的发展历程、核心概念的历史演变,并探讨网络技术未来的前沿方向。我们将学习数据报与数据包的区别、网络架构的设计思想,以及 3D 打印等新技术对网络和社会的潜在影响。


与 Kevin Fall 的对话

我在操作系统原理研讨会的计算机科学会议上遇到了 Kevin Fall。能在这里遇见他非常幸运。

我认为听听他对互联网的看法会很有趣。


TCP/IP 图解指南的诞生 📖

Kevin,你目前是《TCP/IP 图解》的作者。这是如何发生的?你与 TCP/IP 以及过去工作的关系是什么?你在 TCP/IP 方面的背景是怎样的?

我毕业后不久,刚到伯克利时,有人向我演示了可以在不到一秒的时间内将数据包发送到欧洲并返回伯克利。从那时起,网络就成了一个值得关注的有趣领域。

多年以后,我在伯克利 Unix 系统上从事网络实现工作,这让我接触到了高性能计算社区。之后,我在加州大学圣地亚哥分校完成研究生工作后,进入了劳伦斯伯克利国家实验室。

加州大学圣地亚哥分校进行了一些协议和操作系统方面的工作。而在 LBL,我的工作则更多地集中在网络方面,从事网络模拟器和 NS 模拟器等工作。

我对这些内容变得非常熟悉。到了 90 年代初或中期,当互联网开始广为人知时,人们对“TCP/IP 是什么”产生了兴趣。《TCP/IP 图解》这本书是当时的标准参考文本,第一卷至今仍是一本很好的书。

我曾用它来教学,学员来自思科等行业的专业人士。因此我对材料非常熟悉,但随着时间的推移,书中有些内容需要更新。

我曾听说有人被邀请重写这本书,也有人联系过编辑或出版社。但出于各种原因,始终没有实现。于是我提交了我的目录和样章,得到了这份工作,并在大约七年后完成了这项超过一千页的任务。


新版书籍的主要更新 🔄

这是一个你认为需要引入改变但原版中没有的例子。其中一个主要更新是安全

书中新增了约一百页关于安全的内容,介绍了基本的安全原语、需要防范的威胁类型,以及实现这些防护的协议细节。在第一版著作完成时,安全(不仅是密码学部分,还包括防火墙等)几乎还不存在。

书的前面还新增了一章,关于架构基础与设计决策。探讨了设计者在做出设计决策时的思考。我对此一直很感兴趣,作为一个最初从事操作系统工作的人,我关注人们如何提出抽象概念,程序如何访问这些概念,以及背后的架构考量。

我一直对架构领域的论文和思想很感兴趣。


数据报与数据包:被遗忘的区别 📦

昨晚我们谈到,如今人们常常互换使用“数据报”和“数据包”这两个术语,但它们原本并非同义词,有着相当不同的含义,如今这种区别可能已随时间流逝。

我想我在书中的某部分提到了这一点。数据包是一个迷人的新概念,你可以将较大的消息分割成小部分并在网络中传输。但它们最初至少有些变体是作为虚拟电路的一部分。例如,数据包中的目的地是路由表中下一跳的索引,因此你需要提前建立路由。

如果由于某种原因路由失败,你需要做很多工作来回退,这涉及到电路的历史等等。

数据报可能是一个更激进的想法,其最终目的地直接在数据包结构中标识。当我教授这门课时,我会这样解释:如果我以二维空间布局网络,凭借数据报的这种特性,我可以把它从空中扔到任何路由器上,它都能找到自己的路径,因为最终目的地已经列出。

当然,这是一种权衡,因为现在你需要分配更多比特,以应对可能存在的更大数量的潜在目的地。

这些细微差别非常精妙,通过回顾架构历史并思考、了解当时人们的争论,可以获得这些细节。


当前的研究兴趣与未来展望 🚀

那么你现在在研究什么?你认为网络、互联网和系统领域最有趣、你正在尝试解决的问题是什么?

有几个领域我认为很有趣,值得至少提一下其中一个,我们在上面有一些工作。

第一个领域我们涉猎不多。我提到了 Licklider,在书中也引用了他的观点。他和他的同事及前辈们设想,我们不仅拥有最终演变成今天互联网的通信社区,还有一种物理移动物品的方式,类似于全球气动管道系统。你可以把你的东西塞进去,它就能找到路。这将是一个非常酷的东西,但我不认为我们已经实现了,也不确定我们最终是否真的会有。

是的,这在某种程度上是可能的。虽然不是气动的,但结合 3D 打印技术以及信息的自由或轻松传播,变得非常有趣,尤其是当你可以使用塑料以外的材料时。

我手上曾有一个演示品,是一个钛合金 3D 打印的鼻部替代假体。它是钛丝一层层打印出来的。如果你能在设备中装入正确的材料,几乎任何你想创造的实物都可以被创造出来。

甚至扩展到传感器网络领域,人们希望感知世界,甚至驱动世界,但结合按需构建世界的能力,这非常有趣。我在想,这或许不是实现气动管道愿景的方式,但与其移动物品,不如直接制造另一个。

那么,未来会有多远,你只需在车里或背包里携带一个基本系统,然后下载你恰好需要的任何东西?甚至更进一步,就在几个月前,华盛顿特区召开了一个会议,讨论增材制造的安全影响。

我可以向你提出那些问题。是的,比如枪的底把。通常在枪支中,有一个特定部件受到严格监管,它是所有其他部件必须连接的核心部件。有人 3D 打印了一个,而这通常需要许可证。这引发了一个有趣的问题,关于所有这些类似数字版权管理的事物将带来什么影响。

我认为这里有很多政策问题。通常情况是,技术会超越政策制定者理解和制定合理法律的能力。比特与物理对象变得可互换,而我们传统上对物理对象的控制进行监管,但现在我们是否还需要这样做?


总结

本节课中,我们一起学习了 TCP/IP 协议的发展背景和《TCP/IP 图解》书籍的更新历程。我们深入探讨了数据报数据包这两个核心概念的历史区别,理解了网络架构设计中的权衡思想。最后,我们展望了未来,看到了 3D 打印、生物合成等技术与网络结合所带来的巨大潜力与挑战。网络技术不仅关乎连接,更在深刻地塑造着物理世界的创造与规则。

课程 P137:交换机与路由器设计访谈 🖧

在本节课中,我们将跟随Tom Edsall的访谈,了解以太网交换机和IP路由器的设计历史、核心功能、架构演进以及未来趋势。Tom是网络设备设计领域的资深专家,曾主导设计了思科Catalyst系列交换机等众多产品。

访谈对象介绍

今天我们邀请到的是Tom Edsall,我认识他已有多年。

Tom从事交换机和路由器的设计工作已经很久了。

他曾在斯坦福大学攻读硕士学位,毕业后在多家公司工作过。

其中最著名的是思科公司,可以说,他负责设计和部署的以太网交换机与路由器比世界上任何其他人都多。因此,他完全有资格在今天与我们探讨交换机和路由器的设计。

你好,Tom。

交换机和路由器的起源 🏗️

Tom,我的第一个问题是,在CS144课程中,我们学习了以太网交换机和IP路由器及其基本功能。

你能谈谈路由器和以太网交换机的历史吗?它们最初是何时被制造和销售的?是基于CPU还是专用硬件?

好的。

我认为第一台非常成功的以太网交换机,是我们在思科设计的一款名为Catalyst 5000的产品。

Catalyst 5000最初是一个简单的二层交换机,或者说是一个多端口网桥。

它基于我们设计的一些定制硅芯片。

每个端口都使用一个ASIC(专用集成电路)。

一块线卡上有12个端口,因此就有12个这样的ASIC。

然后,一个机箱中可以插入多块这样的线卡。

所有这些设备都通过背板上的公共总线连接。

这款产品是在我们1995年加入思科后不久设计的。

我们当时立即开始研究如何为其增加三层功能,即如何实现路由。

与此同时,思科的主营业务路由器是基于微处理器的,采用MIPS处理器,完全由软件实现。

我们开始研究用硬件实现路由需要什么。

最初的回应是这不可能实现。人们都说:“这太复杂了”,并且解释起来太费时间。

我们当时不太理解问题所在。我们不断追问。

最终我们得出结论,这是可以做到的。只是人们没想过用硬件来实现。

硬件与软件的协同:缓存技术 ⚙️

我们开发了一款商业产品,它允许流量的第一个数据包在硬件中被桥接到系统内的路由板卡上。

那个路由器是在MIPS处理器上运行的软件路由器。

它会像往常一样路由数据包。第一个数据包被发送到软件路由器。

当数据包从软件路由器返回时,我们将返回流与发送到软件路由器的流进行比较。

我们可以看到数据包的不同之处。当然,不同之处在于它有了新的二层报头

于是,我们会记住这个二层报头

之后的所有数据包,我们只需执行从软件中学到的二层报头重写

因此,硬件和软件几乎是完全独立运行的。硬件本质上是在缓存三层转发信息

那么,这种缓存技术今天还在使用吗?

是的。这取决于具体产品。一般来说,我们考虑快速路径慢速路径。你可以把快速路径看作一个缓存。

有时这个缓存可能在硬件中实现,有时可能在软件中实现。

通常,第一个数据包会走慢速路径,或者带有某些选项的数据包也会走慢速路径。

而普通数据包则可以通过快速路径。

缓存技术在这些年时兴时衰,这取决于我们要解决的问题以及解决这些问题的约束条件。

现代交换机的复杂功能 📋

在课堂上,我们学习了基本转发功能:学习二层地址,然后转发,如果不知道地址则广播。

对于三层,我们检查版本号、校验和,然后递减TTL,最后执行最长前缀匹配查找。

但在现代交换机中,它们的功能远不止于此。它们做的事情列表令人望而生畏。

你刚才提到的基本功能,本质上就是我们最初那个缓存信息的硬件包装器所做的事情。

我们做的其他工作还包括大量安全功能。

有时只是简单的检查,比如确保没有零偏移分片。

除了检查版本号,还有这些简单的安全检查。

当然,当你递减TTL时,必须确保如果TTL变为零,要将数据包重定向到本地CPU。

你需要为内部CPU提供各种保护,使其不易受到拒绝服务攻击。

因此,对于发送到本地CPU的控制*面数据包,需要进行各种过滤和限速。

组播的实现完全是一场噩梦,有上百个不同的功能需要正确配置。这是我们做过的最困难的事情。

这些交换机中还必须实现许多监控功能。

最基本也最有用的功能之一叫做交换机端口分析器,我们可以将一个特定端口的所有流量镜像到另一个端口,或者将来自一个端口的所有流量发送到某个分析器。

当然,你可能希望同时运行多个这样的分析器。

你可能还希望远程交换机上的分析器能够监控本地交换机的流量。

因此,你必须想办法通过网络隧道传输这些信息。

此外,还有服务质量、活动队列管理等。路由器和交换机的功能列表非常长。

不同场景下的设备差异 🌐

是的,它们确实是非常复杂的设备。我猜它们也被用于各种不同的地方,比如家庭、企业、广域网、数据中心、接入网、网络边缘。

针对这些不同的应用场景,这些设备、系统以及它们的构建方式是否有本质上的不同?

是的,确实不同。

看看你家里的路由器,它的功能集并不特别复杂,带宽也非常低。

当然,它们通常内置了无线功能。这类设备通常使用某些商用芯片,并运行一个操作系统,可能基于Linux。

更大的设备分为固定外形规格(端口数量固定,无法更换线卡)和大型模块化机箱(可以插入多块线卡和多种不同类型的接口)。

对于小型交换机,其内部架构通常是单芯片交换机

对于更大的系统,单芯片显然不够用,因为端口数量超过了单个芯片的容量,或者整个系统分布在多块线卡,有时甚至是多个机箱或多个机架上。

这些系统倾向于基于交叉开关或某种集中式、相对简单的高性能交换单元,在线卡之间或端口设备之间交换流量。

端口设备本身或线卡,通常看起来很像单芯片交换机,一个设备可能支持48个10吉比特以太网端口或48个40吉比特以太网端口。

在数据中心,重点在于带宽和低成本。

在园区网,对带宽的要求没那么高,但肯定会基于成本,并围绕身份验证和端点管理有许多接入功能。

在广域网,重点将放在带宽、缓冲以及不同类型的接口上,服务质量也变得很重要。

所以,是的,它们有各种不同的类型。

技术演进与架构革新 🚀

这些交换机和路由器多年来不断演进和发展,主要的技术或架构进步是什么让它们能够持续扩展?

主要是来自底层技术(如摩尔定律)的推动,还是有助于网络交换机和路由器的特定技术或特定架构?是什么让它们能够跟上性能需求?

如果我们严格遵循摩尔定律,世界上最快的链路可能只有10吉比特。当然,今天我们交换的速度比这快几个数量级。

因此,网络和网络设备必须经历架构变革,以克服摩尔定律的限制。

我们当然会尽可能利用摩尔定律。

但回顾我参与设计的一些交换机(请记住,这些交换机占据了整个交换机市场的60%到70%,是非常重要的*台),最初的Catalyst 5000产品线基于总线架构,是一个共享总线。

整个交换机的总带宽是每秒1吉比特,它聚合了10兆比特链路和一些100兆比特链路。

但那个总线很快就达到了速度极限。总线的性能取决于单根导线上的信号速度以及能并行放置多少根导线。这就是整个机箱的极限。

该*台的下一代产品,Catalyst 6000(我认为它至今仍是思科价值数十亿美元的产品),大约在1998或1999年交付。它转向了交叉开关架构。

交叉开关架构允许我们在每根导线上实现更快的信号传输,并且端口之间的信号传输可以相互独立。因此,它不再是基于总线的架构。

然而,那并不是一个带仲裁的交换结构。我知道Nick你在仲裁及其重要性方面做了很多研究。但实际上,在2000年至2010年间,世界上大多数网络并没有仲裁功能。

基本上,数据包被发送到交叉开关,并希望它能顺利送达另一端,没有冲突。这样成本更低,也更简单。

大约在2008年至2010年间,我们开始感受到交叉开关的压力,于是为其添加了仲裁功能以提高性能。

同时,还允许数据包在多个交叉开关*面上进行喷洒传输以获得更好性能。因此,我们必须在出口侧进行数据包重排序以保证数据包顺序。

这些就是一些架构上的变化。我们从外部存储器转向了片上存储器。

有一段时间DRAM很流行。现在我们更多地转回嵌入式静态RAM。这只是跟随硅技术发展的趋势。

但总的来说,定制ASIC的封装技术进步速度远不如硅本身。

因此,制造一个更大的芯片比连接多个较小的设备更便宜。

软件定义网络的影响 🤖

好的,谢谢。在课堂上,我们有一位演讲者谈到了SDN(软件定义网络)。

基本思想是向交换转发*面开放更多的可编程控制,无论是来自客户、网络所有者/运营商,还是其控制下的软件。

随着这种变化发生,交换机需要如何改变?你认为它们会如何改变?

这是一个有很大争议的点。

我最终认为,底层硬件不会像许多人想象的那样发生改变。

我们听到的关于SDN的一部分内容围绕OpenFlow展开。OpenFlow可能暗示底层硅芯片需要进行一些架构改变。

但我并不认为这会发生。

我认为底层硅芯片及其使用的字段和结构方式对我们来说已经工作得很好。

无论这是否通过集中式控制器来控制,我认为与是否使用OpenFlow完全正交。

然而,正在发生的另一件事,我认为比SDN更重要的是网络虚拟化

这种虚拟化是通过叠加技术实现的。

有很多不同的叠加技术。VXLAN是一种,NVGRE是另一种,还有STT、LISP、FabricPath、TRILL等。这些技术层出不穷。

我认为行业会收敛到少数几种技术上。我有我的预测,但我们不深入讨论。

但我认为这种叠加技术确实为网络提供了根本价值。

而四年前制造的交换机可能无法实现它,或者无法大规模、高性能地实现它。

因此,我认为新的硬件将支持这些叠加技术,并持续改进叠加技术的功能。

行业前景与职业机会 💼

好的,谢谢。我想称之为SDN。当然。最后一个问题。

如果学生想了解更多关于交换机和路由器设计的知识,我是说,这个领域还有很多工作机会吗?它还是一个不断增长和扩张的领域吗?

我们听到各种说法,认为交换机和路由器的硬件侧正在变成一个更小的领域。我们看到很多人都去谷歌和Facebook工作了。

在这个领域工作仍然令人兴奋且有发展前景吗?

这是个有趣的问题。我从1985年就开始做这个了,时间很长。

期间有过非常激动人心的时期。当我们首次提出交换技术,行业正在兴起,互联网开始蓬勃发展,网络变得重要时,那是一段非常激动人心的时期。

然后,我认为有一段时期没有太多新事物发生。是的,我们要造更快的交换机,这里那里调整一些旋钮。那大概是2000年到2010年这段时间。

我认为我们现在正在经历一场变革。我认为,其中的催化剂实际上包括你们所做的一些工作,比如OpenFlow和整个SDN网络的理念,以及让我们实现虚拟化。

这项技术并非必然来自单一源头,而是在许多实验室中酝酿,现在真正爆发出来。

对我来说,再次进行互联网交换机设计在智力上具有挑战性,也非常有趣。

这项技术将会成熟并放缓,之后可能会有其他新事物出现。

在这个不断发展的行业中,开发自己硬件的公司越来越少。当然,思科还在做。瞻博网络开发了一些自己的硬件。

对于初创公司来说,获得资金开发新硬件非常困难,因此它们倾向于使用商用芯片。

所以,如果你想设计交换机硬件,我认为那个领域的机会变少了。

然而,我确实认为在那个领域还有一些非常有趣的事情可以做。就我个人而言,我很幸运能在一家初创公司工作,目前就在一家开发交换机硬件的初创公司。

我有一长串想做的事情清单,但我无法全部完成。我相信其他人也有关于可以在交换机硬件中实现的酷炫想法清单。

所以,并不是所有伟大的想法都被想到了。情况没那么糟,但也不像90年代末那样。

如果你有实习机会,请把详细信息发给我,我会转发给班级。我非常乐意雇佣实习生,我会招很多实习生。

好的,太好了。我们聊聊这个。非常感谢你,Tom。真的非常感谢。这非常有趣,提供了我们在课堂或教科书中通常无法获得的见解,非常有用。

谢谢。

好的,谢谢。期待很快再见到你。

总结 📝

本节课中,我们一起学习了交换机与路由器的设计演进。从基于总线的早期架构,到交叉开关和带仲裁的交换结构,硬件设计不断克服物理限制以满足性能需求。同时,软件定义网络和叠加虚拟化技术正在塑造网络的未来。尽管硬件设计的机会可能更加集中,但创新空间依然存在,网络领域持续经历着激动人心的变革。

课程 P138:TCP拥塞控制的演进与挑战 🚀

在本节课中,我们将与Nandita Dukapati博士对话,探讨TCP及其拥塞控制算法(如TCP Reno、New Reno等)在现代网络和应用中面临的局限性,以及业界为克服这些限制所提出的改进机制。我们还将展望未来拥塞控制可能的发展方向。


TCP的局限性 🔍

上一节我们介绍了课程背景,本节中我们来看看TCP及其经典拥塞控制算法(如TCP Reno、New Reno)存在哪些主要问题。

随着网络带宽的增长和各种新型应用的出现,TCP在许多方面受到了挑战。以下是几个关键问题:

  • 基于丢包的机制问题:TCP Reno、New Reno乃至较新的Cubic等算法本质上是基于丢包的。它们持续向网络发送数据,直到网络队列溢出并触发丢包,然后才据此调整速率。问题在于,要维持高速链路(如10Gbps或200ms RTT的链路)的速率,所需的丢包率必须极低(例如每8万个报文段丢一个包)。这在十多年前物理学家通过跨洋链路传输大量数据时,就是一个大问题。
  • 短流性能不佳:考虑Web流量或数据中心内的RPC(远程过程调用),它们通常是极短的请求-响应事务。每个TCP连接都以一个RTT的握手开销开始,如果请求或响应本身很短,这个开销就非常显著。此外,慢启动算法需要时间逐步增大拥塞窗口,这对于短流来说太慢了。测量显示,在Google服务器上,经历丢包的HTTP响应耗时大约是无丢包情况下的10倍。
  • 缓冲区大小的影响:如今互联网交换机和路由器拥有巨大的缓冲区。早期的拥塞控制算法旨在填满缓冲区直至溢出,以追求高吞吐量。但过大的缓冲区会引入高延迟,尤其影响那些只持续一两个RTT的短事务。另一方面,缓冲区极小的设备也存在问题,它们容易导致突发性丢包,而TCP会误判为拥塞并大幅降低窗口,导致链路无法被充分利用。
  • 浏览器行为与移动网络的挑战:现代浏览器会同时打开数十个连接以下载网页资源,这类似于“瞬时拥塞”场景,容易导致缓冲区溢出和排队延迟激增。此外,移动网络中常见的链路波动(二层问题)会欺骗TCP,使其误认为网络极度拥塞,从而触发指数退避的重传超时。

改进机制的分类 🛠️

了解了TCP的诸多挑战后,我们来看看业界提出了哪些改进机制来克服这些局限性。这些机制大致可分为三类。

以下是三类主要的改进机制:

  1. 仅需终端主机修改的机制:这类改动只需要服务器端或客户端进行变更。例如,一系列新的拥塞控制算法,如Cubic TCP、HighSpeed TCP和Fast TCP,旨在解决大带宽延迟积网络中维持高吞吐量的问题。它们相比New Reno对丢包的反应不那么剧烈,并在有可用带宽时更快地提升速率。其中,Cubic和HighSpeed TCP仍是基于丢包的,而Fast TCP是基于延迟的算法。
  2. 仅需网络设备修改的机制:例如,主动队列管理算法,如最*的CODEL和PIE,它们通过选择性丢包向TCP发送方发出队列正在累积的信号。
  3. 需要终端与网络协同修改的机制:例如RCP、XCP、MaxNet或DCTCP,它们需要中间网络设备和终端系统同时更改。终端系统会获得明确的速率调整通知(如ECN的一个比特,或RCP/XCP的多字节信息)。

在这三类中,第一类(仅终端修改)最为成功,主要因为其易于部署和穿越中间设备。


针对短流和Web的优化 ⚡

上一节我们介绍了改进机制的整体分类,本节我们聚焦于第一类中那些专门为优化短流和Web性能而设计的机制。

为了加快网页加载速度,业界提出了多种机制来加速互联网上的短事务。

以下是几个关键优化示例:

  • TCP Fast Open:允许在TCP握手(SYN包)中携带数据。对于通常能放入一个数据包的Web请求,客户端无需等待一个完整的RTT握手完成后再发送请求,可以随SYN包一同发出,显著减少了页面加载时间。
  • 增大初始拥塞窗口:TCP的初始拥塞窗口长期保持在3个报文段,最*在许多主流开源操作系统中已增加到10个报文段。
  • 比例速率降低:使TCP的快速重传算法更高效。传统的快速重传算法被发现要么过于突发,要么过于保守。PRR算法*滑了快速重传和快速恢复过程,只重传确认为丢失的数据,使得短流的丢包恢复更加*滑。
  • 尾部丢包探测:重传超时对短流的影响是灾难性的,基于RTO的恢复比快速重传/恢复慢10到100倍。TLP提案试图将RTO转化为快速重传,这对于减少短流的尾部延迟意义重大,因为短流中约70%的丢包发生在尾部。

数据中心内的TCP优化 🏢

在像Google、Facebook这样的大型数据中心中,有机会同时更改连接的两端(服务器和客户端),以解决数据中心特有的限制。

数据中心网络的问题在许多方面与互联网相似,但也有关键差异。相似点包括对延迟(尤其是尾部延迟)的极度关注,以及缓冲区过大或过小的问题。主要区别在于,在数据中心内,我们可以同时改变服务器和客户端。

以下是数据中心内的一些优化方向:

  • 更精确的定时器:在互联网上,重传超时必须设置得非常保守(例如默认1秒),以涵盖各种网络状况。而在数据中心,网络RTT通常在微秒级,因此可以将这些定时器设置得更精确、更紧凑,这对降低RPC的尾部延迟至关重要。
  • 部署需要交换机参与的机制:例如,微软研究院与斯坦福合作的DCTCP工作就很有意义。通过交换机提供的一个比特信息(ECN),终端主机就能更好地决策如何调整速率。

因此,更好的定时器集成(使其更紧凑)以及能够部署需要交换机参与的机制,是数据中心与互联网环境的重要区别。


未来展望:超越AIMD? 🔮

到目前为止讨论的所有改进,都是对多年前提出的基本AIMD拥塞控制机制的修改和变体。它们都使用相同的基本机制,只是以不同方式修改滑动窗口。

那么,展望未来15到20年,我们还会继续使用今天这种慢启动加AIMD的拥塞控制吗?还是会被一个或多个工作原理迥异的新方案所取代?

这是一个很好的问题。我们真诚地希望不会仅仅继续使用基于AIMD的协议。原因在于,我们已经发现有很多方法可以做得更好。目前,我们实际上是在针对每个具体问题提供“点对点”的解决方案:

  • 针对短Web流,我们优化慢启动阶段(它们很少进入AIMD阶段)。
  • 针对移动网络,我们尝试不同的方法。
  • 针对视频流,因其流量模式与长FTP流或短Web事务不同,我们进行特殊处理。
  • 针对数据中心和移动网络,我们分别采用不同的优化。

我们真正需要的是退一步思考:能否设计出一种适用于所有网络和所有应用模式的拥塞控制,而不是把每个问题都当作特例来处理?

在这个方向上,*期MIT的Remy研究令人关注,它利用机器学习算法自适应地生成拥塞控制算法。这是一个有趣的方向,我们很期待看到这些自动生成的算法在实践中的表现。另外,尽管需要路由器协助的拥塞控制由于部署难度大而未能广泛部署,但随着OpenFlow和SDN等技术的发展,未来我们可能会看到网络在拥塞控制中扮演更积极的角色。我们对这两个方向的前景充满希望。


总结 📝

本节课中,我们一起学习了TCP拥塞控制在现代网络下面临的诸多挑战,包括基于丢包机制的局限、对短流性能的影响、缓冲区大小带来的问题以及移动网络和浏览器行为引入的新难题。我们探讨了针对这些问题的三类改进机制,并详细了解了为优化短流和Web性能而提出的具体技术,如TCP Fast Open和尾部丢包探测。我们还看到了在可控的数据中心环境中,通过调整定时器和部署如DCTCP等机制所能实现的优化。最后,我们对未来进行了展望,讨论了超越传统AIMD框架、迈向更通用和智能的拥塞控制的可能性。

课程 P139:网络架构演进与未来趋势 🌐

在本节课中,我们将跟随思科首席架构师 David Ward 的分享,回顾互联网与路由技术的发展历程,并探讨当前最前沿的技术趋势,如分段路由和软件定义网络。


从学术研究到商业互联网 🧪

David Ward 的职业生涯始于 90 年代中期的明尼苏达大学研究生院。当时,他参与了一个旨在证明“由高速网络连接的工作站集群,其计算能力可以超越超级计算机”的项目。

为了实现这个目标,他们部署了世界上第一个生产级的 ATM 网络,连接了 Sun 和 SGI 工作站。为了将各地的超级计算机连接起来以证明其计算能力,他们又构建了第一个广域 ATM 网络,连接了匹兹堡、明尼苏达、圣地亚哥等地的超级计算机中心。

然而,超级计算机之间使用一种名为 HIPI 的协议进行通信,而当时并没有现成的 HIPI 交换机。因此,David 和他的团队不得不发明了 HIPI 交换机以及 HIPI over ATM 的技术。在这个过程中,他们深入学习了如何构建高性能的广域网数据包生成器。

随后,他的工作转向升级中西部大学网络以及明尼苏达大学连接到当时还是 NSFNet 的互联网。在从事这些高速网络工作的同时,他发现自己对物理有机化学的博士研究非常困难,而网络技术则相对简单且有趣,于是他决定转向这个领域。


创业、收购与思科生涯 🚀

David 加入了一家初创公司,致力于开发 HIPI 交换机。他们的商业计划是连接全球所有的超级计算机。但这个计划面临两个问题:一是像 NASA 戈达德中心这样的庞大机构,只需要一台交换机;二是超级计算机价值数千万美元,而交换机只卖 35 万美元,市场容量有限。

就在此时,互联网开始从 NSFNet 走向商业化。他们团队利用 FPGA 和 ASIC 技术,在运行开源 BSD 系统的 Unix 机器上,构建了世界上第一台分布式转发路由器。这家初创公司后来被 Ascend Communications 收购,而 David 则加入了另一家后来被思科在 1999 年收购的小型初创公司,并一直工作至今。

在思科,David 主导设计了多款核心路由器,并担任了 iOS XR 操作系统的首席架构师。他提到,早年在大学进行高性能并行计算和操作系统的研究,为他后来设计多线程、模块化的网络操作系统奠定了深厚的基础。


互联网协议与架构的演进 🔄

在构建 NSFNet 和后来的商业化互联网时,服务提供商之间需要大量的协议扩展来实现互联和服务构建。David 和他的同事们共同发明了当今互联网架构的基础协议。

以下是当时为解决特定问题而发明的一些关键技术:

  • MPLS:当链路带宽受限且无法快速获得电路时,用于实现带宽预留和流量工程。
  • 三层 VPN:用于连接使用重叠地址空间的企业网络,解决正确的 IP 路由问题。
  • BGP, OSPF, ISIS:构成了互联网路由和交换的核心协议栈。

这些发明大多是出于当时的实际需求,并且看着它们被快速部署到全球网络中,是一段非常有趣的经历。


分布式路由与集中式控制的融合 🤝

谈到软件定义网络时,David 提出了与常见观点略有不同的见解。他认为,完全分布式的、自主运行的路由器网络,在应对拓扑故障时能提供最快的保护和恢复能力,这是互联网设计之初应对核战威胁理念的现代体现。

然而,分布式路由也存在局限。为了扩展互联网规模,IP 地址在自治系统之间和内部被大量汇总。这导致了一个问题:当你想使用 MPLS 等技术在两个被汇总的地址之间建立隧道时,由于看不到对方的具体地址,操作会变得非常复杂。

因此,他主张将两者结合:

  • 分布式路由网络:负责快速故障恢复和基础可达性。
  • 逻辑集中式控制器:拥有跨越汇总边界的全局拓扑视图,可以轻松地建立端到端的路径,并实施服务质量等策略。

这种“增强型”模式结合了二者的优势:分布式路由擅长扩展,而集中式控制擅长跨越管理边界进行路径优化。


当前最前沿:分段路由技术 ⚡

David 目前最关注的技术是 分段路由。这项技术的目标是简化 MPLS 网络、流量工程和 VPN 服务,其核心方法是减少协议和网络状态

传统 MPLS 流量工程使用 RSVP-TE 协议,需要路径上的每台设备都保留状态,存在扩展性问题。而分段路由采用了不同的思路:

  1. 它利用现有的链路状态协议,在泛洪路由器、接口的 IP 地址和邻接关系时,“顺便”携带一个标签信息。
  2. 这样,网络中的每个节点都获得了完整的拓扑信息和标签映射,但无需为每条隧道保留状态。
  3. 当需要建立一条特定路径时,SDN 控制器 或头端设备只需要计算并压入一个标签栈,数据包就会按照预定路径转发,并能天然地利用等价多路径等特性。

其核心优势可以用一个简单的对比来概括:

  • 传统 RSVP-TE信令协议逐跳建立状态,保留带宽。
  • 分段路由头端编程标签栈,网络无状态转发。

这项技术解决了互联网架构中一个长期存在的问题:如何有效地在大量并行链路上进行流量负载均衡。它保留了快速重路由和流量工程的能力,同时极大地简化了操作。


迈向更智能的网络规划 🧠

David 指出了当前 IP/MPLS 网络在流量规划方面的两个主要问题:

  1. 基于头端的负载设计:隧道发起者只能基于自己看到的拓扑信息(通常是预留带宽,而非实际利用率)来规划路径,无法感知网络其他部分的实时负载。
  2. 缺乏准入控制:广域网上几乎没有真正的准入控制,主要依靠历史数据进行预测,无法应对瞬时流量波动。

为了解决这些问题,他们正在推动将更多实时信息(如链路延迟、利用率、抖动、丢包率)通过路由协议泛洪到网络中。这些信息不会被用于实时运行 SPF 算法改变路由,而是被推送到一个集中式控制器。

控制器拥有全局的实时拓扑和负载视图后,就可以做出更智能的决策:

  • 克服最短路径路由的限制,充分利用所有已部署的带宽。
  • 实现基于实时状态的流量调度和保护恢复。
  • 为大数据迁移、内容缓存加载等“大象流”提供确定的网络路径。

这种方法将现代计算机科学的理念(数据推送、集中分析)应用于网络,旨在移除不必要的网络状态,实现更高效、更可控的广域网。


总结与展望 ✨

本节课我们一起回顾了互联网从学术研究到商业化的关键发展节点,以及核心路由协议的诞生背景。我们深入探讨了分布式路由与集中式 SDN 控制器的融合价值,并重点介绍了分段路由这一革命性技术,它通过减少网络状态和协议复杂性,为流量工程和负载均衡带来了新范式。最后,我们展望了通过向集中式控制器推送实时网络数据,来实现更智能、全局优化的网络流量调度和规划的未来。

David 最后鼓励对网络技术感兴趣的学生和从业者参与到相关的标准组织和开源项目中,因为网络领域,尤其是路由技术,依然充满活力与挑战。

课程 P14:IPv4 地址详解 🧩

在本节课中,我们将学习 IPv4 地址的核心概念,包括其结构、子网掩码的作用以及如何通过简单的计算来确定网络地址和主机地址。我们将通过一个具体的测验示例来巩固这些知识。


概述

IPv4 地址是互联网中设备通信的基础标识。理解其构成和子网划分原理,对于网络配置和故障排查至关重要。本节我们将解析一个具体的地址与掩码组合,并计算出其网络地址。

IPv4 地址结构

一个 IPv4 地址由 32 位二进制数组成,通常以点分十进制表示,例如 192.168.1.1。它主要包含两部分:

  • 网络部分:标识设备所属的网络。
  • 主机部分:标识网络中的特定设备。

区分这两部分的关键是子网掩码

子网掩码的作用

子网掩码同样是一个 32 位的数字,其作用是“掩盖”掉 IP 地址中的主机部分,从而显露出网络地址。掩码中连续的“1”对应 IP 地址的网络位,“0”对应主机位。

计算网络地址的公式是:
网络地址 = IP地址 AND 子网掩码

以下是理解该计算的关键步骤列表:

  1. 将地址转换为二进制:首先把 IP 地址和子网掩码都转换成二进制形式。
  2. 执行按位与(AND)运算:对每一位进行逻辑与操作(1 AND 1 = 1, 其他情况均为 0)。
  3. 转换回十进制:将得到的二进制结果转换回点分十进制格式,即为网络地址。

测验示例解析

现在,我们来看一个具体的测验。题目给出了源/目的 IP 地址和子网掩码,要求我们进行标记或计算。

这张图展示了一个测验的初始界面,其中包含了需要分析的 IP 地址和子网掩码。

这张图很可能展示了测验的后续步骤或答案,例如通过上述“按位与”运算,得出了该 IP 地址对应的具体网络地址。


总结

本节课中,我们一起学习了 IPv4 地址的基本结构,明确了网络部分与主机部分的区别。我们掌握了子网掩码的核心作用——用于计算网络地址,并熟悉了“IP地址 AND 子网掩码”这一关键公式及其计算步骤。通过实际的测验示例,我们巩固了如何将理论应用于实践,从而确定任何给定 IP 地址所在的网络。

课程 P140:BGP - 互联网的粘合剂 🧩

在本节课中,我们将学习边界网关协议(BGP)的历史、工作原理、优势与挑战。BGP是连接互联网不同自治系统的核心协议,理解它对于理解互联网的运作至关重要。


BGP的起源与演变

上一节我们介绍了课程概述,本节中我们来看看BGP是如何诞生的。

BGP本质上是将互联网不同部分粘合在一起的“胶水”。它与互联网共同成长。在20世纪80年代ARPANET运行时,网络本质上是一个树状结构,核心是ARPANET本身,其他网络连接到它。当时并不需要一个复杂的域间路由协议。

当NSFnet投入使用时,网络需要支持更灵活的互联方式。网络之间不仅连接到NSFnet骨干网,也可能彼此直接连接。由于拓扑结构可能变得循环,处理路由环路变得必要。因此,BGP被设计用于支持更通用拓扑结构上的路由。

随着时间的推移,BGP随着互联网的发展而演变,以应对可扩展性问题、地址空间耗尽以及需要承载大量地址块等挑战。同时,随着域间业务关系和服务提供商希望为客户提供的服务不断演变,BGP也在适应这些变化。例如,服务提供商现在更需要能够选择一条可能更长但经济上更有利或性能更好的路径。


BGP的优势与弱点

上一节我们了解了BGP的演变,本节中我们来看看它的核心特性。

BGP使互联网成为互联网,它必须协调不同服务提供商及其他网络参与方相互竞争和冲突的目标。从这个意义上说,BGP解决了一个非常困难的问题,并且至少是一个可行的解决方案。它表现出显著的适应能力,能够应对安全性、可扩展性、业务关系乃至安全方面的担忧。

然而,BGP难以扩展,配置复杂。协议本身在某些方面相当简单:我向邻居通告路径,他们在路径开头添加自己,选择他们最喜欢的路径,然后通告给他们的邻居。但所有复杂的操作都在于BGP的配置方式。这也是BGP难以教授的原因之一,因为协议规范或教科书主要只描述了基于路径的逐跳路由信息传播,对配置方式提及甚少。

因此,学习曲线相当陡峭。人们由于经验不足或路由器中低级的错误配置机制而在配置BGP时犯错。我们经常看到由操作员错误导致的中断。一个很好的例子是多年前巴基斯坦电信试图在巴基斯坦境内屏蔽YouTube访问,却意外地向全球宣告他们是到达YouTube的最佳路径,导致整个互联网都相信了这一点。

所以,BGP确实容易受到这类“蝴蝶效应”的影响,即互联网某处的一个小故障或小配置错误可能产生严重的全球性后果。从这个角度看,它最初并非被设计成一个像如今互联网这样关键基础设施所需的健壮且安全的协议。


BGP的安全性与路径选择

我们常听说攻击者能够通过BGP对等会话秘密宣告路由,从而破坏路由。您认为这在实践中经常发生吗?

在实践中,互联网上的许多攻击者实际上希望互联网保持正常运行,因为他们真正试图做的是对特定受害者发起拒绝服务攻击或进行网络钓鱼攻击。因此,总的来说,大多数攻击者不希望BGP瘫痪。第二个原因可能是对手通常无法访问支持BGP的路由器来进行操纵,或者不具备这样做的技能。所以,这肯定不如我们在互联网上看到的其他形式的网络攻击那么普遍。

话虽如此,我们每年仍会看到几次非常引人注目的中断,有时由操作员错误引起,有时方式不明,不清楚是故意还是事故。所以这无疑是一个巨大的漏洞,当它失效时,可能比对单个受害者的攻击产生更广泛的全球影响。因此,它仍然是一个重大的安全问题,但可以说,它不如我们在终端主机上看到的更有针对性的攻击形式那么普遍。


路径通告的局限性

路径矢量传输或通告给邻居的方式常被提及的一个限制是,当对等方向我通告一条路径时,我不知道他们实际上是否会遵循该路径。第二点是,他们在可以通告给我的众多路径中选择他们想要通告给我的那一条,因此可能存在我更喜欢但他们甚至没有告诉我的替代路径。这在实践中是一个很大的限制吗?

我认为这在实践中确实是一个值得关注的问题。例如,ISP的客户可能希望选择一条避开可能进行窃听或审查的特定国家的路径。这是一个很好的例子,说明你可能希望选择避开特定中间域的路径,但却无法做到,因为可能你的所有提供商都没有向你提供这样的路径,即使在实际的拓扑图上可能存在这样的路径。

也可能存在这样的情况,因为路由决策不是基于性能做出的,所以可能存在一条性能非常好的路径,在实际的拓扑图上可用,但你却看不到。一个很好的例子是多年前地中海发生中东光缆切断事件时,许多人开始绕地球另一端路由流量。我从多家运营商那里听说,并不是没有可用的路由,而是因为他们恰好学到的路由受到更多限制,他们也被迫让流量绕地球另一端走,有时延迟要高得多。

所以,我认为这些事情确实重要。但也很公*地说,如果你有多个提供商,你可能会从每个提供商那里得到一条路径,仍然可以获得你可能希望从一个提供商那里获得的某些路径多样性。


路由收敛问题

BGP常被提及的另一个问题是在发生路由变更后其收敛速度。您能简要概述一下问题是如何发现的以及目前的状况吗?

BGP和收敛有两个问题:一是系统是否完全收敛,即是否可能所有这些域根据本地选择不断相互影响,改变主意,永远无法达成全局一致;二是即使它们达成全局一致,速度有多快。在这个过渡期间,数据包可能会丢失、形成环路或乱序送达。人们发现,当Skype通话或Google Hangouts中断时,最有可能的原因是BGP收敛行为,而不是网络拥塞。

关于第一个问题,确实可能存在我想通过你路由、你想通过其他人路由、而他又想通过我路由的情况,我们不断相互影响,改变主意。但在实践中,这种情况被认为并不经常发生。原因是BGP首先是一个“金钱路由”协议,而不是数据包路由协议。数据包路由只是一个不错的副作用。因此,当我作为一个自治系统选择路由时,是基于经济因素:我是否需要付费才能通过你发送流量(因为你是我的提供商)?我通过你发送流量是否能获得收入(因为你是我的客户)?或者这是否是财务中性的(因为你是我的对等体)?最终,这种永久性的协议振荡暗示了某种奇怪的财务动态,即每个人都能在一个循环中赚钱,这在逻辑上不太可能。

关于第二个收敛速度的问题,多年前BGP收敛需要几分钟甚至更长时间,相对于许多实时应用所需的50毫秒或更少的目标来说,这绝对很长。部分原因是BGP会一个接一个地探索替代路径。所以,如果我使用的路径被撤销,我会探索下一个最偏好的路径,而该路径实际上可能与我刚丢失的路径命运相同。它们可能共享一个共同的链路。BGP只通告整个路径,它不会告诉你任何关于可能影响许多路径的共享资源的信息。因此,我和我的邻居们一个接一个地探索它们,最终可能导致探索这些路由的指数级迭代过程。

这种情况已经有所改善,因为驱动我从一个决策转向下一个决策的计时器这些年来已经缩短。坦率地说,即使多年前我们研究这个问题时,大多数BGP路由都异常稳定,每次持续十天或两周。互联网上只有少数不稳定的目的地频繁上下线,这被认为不是由路由振荡引起的,而是由设备实际上上下线导致的。在实践中,这些目的地极不受欢迎。它们要么因为一开始就无法到达而不受欢迎,要么因为不受欢迎而没有人关心确保它们周围的网络稳定。总而言之,这意味着互联网上的绝大多数流量所经过的路径通常稳定数天甚至一两周。

因此,在某种意义上,大量的研究、路由器软件的改进以及操作实践的改进,意味着BGP收敛虽然仍然重要,但远不像15年前看起来那样混乱。


BGP的未来与替代方案

今天看BGP,您认为它是一个存在了很久的“创可贴”式解决方案,还是您相信并希望它作为域间路由协议在未来长期存在?如果您有机会重新设计,您会用类似还是完全不同的东西替换它?

BGP是我又爱又恨的协议。在某种意义上,它已被证明具有相当强的可演化性,并且多年来发生了巨大变化。Jakob Rexford多年前在一个演讲中称BGP为“三张餐巾纸协议”,因为最初设计时它是在三张餐巾纸上描述的。而我会说它现在是“厨房水槽协议”,因为其决策过程的步骤数量、传递的属性数量、BGP中可以处理的不同种类事物的数量,所有这些都变得越来越复杂。这部分是一种“成功的灾难”——可以用BGP做许多远远超出其最初设计目的的事情。所以,这证明了它的可演化性。但这也意味着它变得如此复杂、难以配置,并且非常不安全,因为最初设计时没有用于签名和验证路由信息的机制,也没有关于哪些自治系统被允许为特定地址块发起信息的可靠注册表。所以现在我们正试图“把猫放回袋子里”,通过整合大量安全基础设施来实现,而这实际上事后做起来相当困难。

从这个意义上说,BGP已经演变成一个相当笨重的状态。然而,如果你替换BGP,你仍然需要协调一个事实:不同的域拥有不同的自治权,并且对他们希望如何处理流量有不同的优先级。因此,我真正感兴趣的一点是,域之间的经济关系在单个数据包或路由协议消息的时间尺度上展开,这对于经济关切来说是一个非常小的时间尺度。如果你看看服务器领域发生了什么,虚拟化使得基础设施的所有者与实际上在其上运行应用程序的方(可能属于在属于像Google、Microsoft或Amazon这样的公司的服务器上运行的租户的虚拟机)真正分离成为可能。

因此,我对我们现在也可以虚拟化网络的想法很感兴趣。如果我能拥有一个跨越多个方拥有和管理的设备的虚拟网络,然后在该虚拟拓扑上控制自己的命运,那将是很棒的。这样,业务关系就不重要了,它是我与我的虚拟组件所嵌入的基础设施方之间的关系,而不是我与并排的邻居或更糟的、与我相隔多跳、对我没有责任也没有可见性的域之间的关系。所以我认为,如果我们利用过去十年虚拟化方面的一些创新,我们可以构建一个更加灵活、同时仍然认识到存在真正的自治创收方的路由系统。


给未来研究者的建议

如果有人正在观看并考虑攻读研究生,对网络感兴趣,域间路由仍然是一个有趣的话题吗?它是否再次变得有趣?您有什么建议?

我认为它在两个方面仍然有趣,也许与15年前不同。一是重新思考在新的经济现实中域之间如何关联,利用虚拟化,利用大型内容提供商非常接*其客户(通常只有一两跳之遥)这一事实,使得网络在某些方面比BGP设计时更加扁*。因此,我认为重新审视域间如何互联,考虑到视频和内容分发,以及虚拟化和软件定义网络,是一个有趣的机会。

总的来说,我们发现互联网上任何跨域的东西都很糟糕。在域内部署服务质量、安全性、IPv6、组播等已经足够具有挑战性,但一旦你需要50,000方合作,几乎不可能实现有原则的变革。因此,我认为如今许多关于BGP更有趣的工作更多地关注增量部署、增量部署的激励措施,以及即使只有一小部分互联网采用技术变革也能获得一些安全性、可扩展性甚至经济收益的解决方案,然后希望它能激励其他人参与。所以我认为我们已经进入了一个领域,在这个领域,关于BGP的工作可能更侧重于如何以战略方式演进它,而不是一个全新的BGP设计会是什么样子。


总结

本节课中,我们一起学习了边界网关协议(BGP)。我们探讨了它的历史演变,了解了它作为互联网“粘合剂”的核心作用。我们分析了BGP的优势,如其解决复杂协调问题的能力,也审视了它的弱点,包括配置复杂性、安全漏洞和对操作错误的敏感性。我们还讨论了路径选择、收敛问题以及BGP的未来发展方向。理解BGP对于深入理解互联网的架构和运作原理至关重要。

📡 课程 P141:云管理 Wi-Fi 网络与 Meraki 的创业之路

在本节课中,我们将学习无线网络的实际部署挑战、云管理网络架构的优势,以及从学术研究到成功创业的历程。课程内容基于 Meraki 公司 CEO Sanjit Biswas 的访谈。


🌐 无线网络的实际挑战:从 Roofnet 项目谈起

上一节我们介绍了课程背景,本节中我们来看看 Sanjit Biswas 在 MIT 的 Roofnet 项目中获得的实际经验。

Roofnet 项目旨在为剑桥市的学生构建一个研究性的宽带网络原型。该项目之所以得名,是因为团队将天线安装在学生公寓的屋顶上,并编写了网状网络软件来路由数据包。

以下是该项目揭示的几个关键发现:

  • 链路行为复杂:与当时“链路要么通要么不通”的普遍认知不同,实际无线链路的包送达率可能在 30% 到 70% 之间波动。
  • 影响因素多样:链路质量会随时间、调制方式和干扰而变化。网络内其他设备的传输会产生自干扰,显著影响链路性能。
  • 应用层影响巨大:单个用户的行为(如使用 BitTorrent 下载大文件)会显著影响整个网络的性能,这体现了网络问题具有层次化的特点。

这些在真实世界部署中观察到的现象,与模拟环境中的结果大相径庭,为后续研究提供了宝贵的数据。


☁️ 云管理 Wi-Fi 网络的诞生与优势

从 Roofnet 的实践中,团队发现了大规模网络管理的核心痛点,这直接催生了 Meraki 的云管理模式。

当网络中设备数量从单个扩展到数十、数百甚至数千时,配置和管理的一致性成为巨大挑战。传统的单点配置方式(set-and-forget)不再适用。

云管理网络为客户带来了以下核心益处:

  • 集中化配置与管理:IT 管理员可以从一个中心点,统一配置和管理全球范围内分支机构的网络设备(如接入点、交换机),确保策略一致。
  • 远程可视性与监控:即使远在千里之外,管理员也能清晰地看到网络的运行状态和统计数据。
  • 简化的运维与升级:安全更新、功能增强等软件升级可以通过云端统一、无缝地部署到所有设备上,无需手动操作每个硬件。

这种模式对于拥有多个校区的大型学校或在全球设有分支机构的企业来说,在实践上极具吸引力。


⚙️ 技术架构:与传统方案的差异

那么,云管理网络在技术实现上与传统方案有何不同?

最大的区别在于架构。传统 Wi-Fi 网络通常需要一个物理的 控制器(Controller) 设备安装在本地机房,以实现集中管理。这在多站点场景下难以扩展。

Meraki 的方案是:

  1. 功能内置于接入点:所有数据转发(数据*面)功能仍由本地接入点(AP)直接处理。
  2. 云端虚拟控制器:管理、配置、统计收集等控制*面功能被虚拟化为一个云端的 Web 服务。
  3. 安全加密通道:设备与云端通过一个加密的、低带宽(约 1 kbps)的通道连接,类似于 IPsec 隧道,使用公钥加密技术保障安全。

这种架构实现了软件定义网络(SDN)的理念,将控制*面与数据*面分离,并使新功能可以像软件服务一样快速迭代和部署。


🔮 未来展望:云管理是必然趋势吗?

软件定义网络和云管理的理念正在改变整个行业。那么,这是否是所有网络的未来?

虽然网络市场庞大,很难一概而论,但向云管理发展的趋势是明确的。这主要是出于对效率和简洁性的追求。正如企业邮箱从自建的 Exchange 服务器转向 Gmail 等云服务一样,网络基础设施的管理也很有可能遵循同样的路径。

Meraki 的业务也从最初的无线网络,扩展到管理 交换机(Switch)安全网关(Security Gateway) 等有线设备,为用户提供跨越有线和无线的统一策略管理。

未来,随着物联网设备(如智能恒温器、健康追踪设备)的激增,网络将面临新的挑战,例如如何认证这些无用户界面(UI-less)的设备,以及如何管理海量设备带来的容量和争用问题。这些都将成为有趣的研究和工程课题。


💡 给未来创业者的建议

从 Roofnet 的研究项目到创立 Meraki 并将其成功发展,Sanjit Biswas 分享了给有志于创业的学生的建议。

创业旅程中,每一阶段的挑战都不同。关键在于运用在工程训练中学到的 “第一性原理”思维 来解决问题。就像在计算机网络课(如 CS244)上从零开始编写 TCP 协议栈FTP 客户端 一样,创业也是从一个想法开始,明确接口,然后构建实现。

许多学生认为自己需要商学院背景或领域专家,但实际上,顶尖学校的学生完全有能力自己摸索出道路。硅谷许多非常成功的公司都是由此前毫无经验的学生创立的。

核心建议是:相信自己的能力,不要过于畏惧那些在该领域深耕多年的“专家”,脚踏实地去尝试。不要过多地纠结于“相关研究”,而是亲自去实践,从基本原理出发解决问题,你可能会对自己的能力感到惊讶。


📝 课程总结

本节课中我们一起学习了:

  1. 真实世界无线网络部署的复杂性,包括链路波动和跨层影响。
  2. 云管理 Wi-Fi 网络如何解决大规模网络配置、管理和升级的难题。
  3. 云管理架构的技术原理及其与传统控制器模式的区别。
  4. 网络管理向云端迁移的必然趋势,以及未来物联网带来的新挑战。
  5. 从研究者到创业者的心路历程,以及基于第一性原理解决问题、勇于实践对创业者的重要性。

课程 P142:Dan Boneh 访谈——安全 🔐

在本节课中,我们将学习斯坦福大学教授 Dan Boneh 关于密码学与计算机安全的访谈内容。我们将了解他进入该领域的经历、嵌入式设备的安全隐患、斯诺登事件后的安全启示,以及为学生推荐的相关课程。


Dan Boneh 是斯坦福大学的教授,主要研究密码学和计算机安全。他从小就对密码学产生了浓厚兴趣,并在大学期间深入探索了这一领域。密码学结合了深奥的数学理论与实际应用,例如现代网络通信中广泛使用的椭圆曲线迪菲-赫尔曼密钥交换。

上一节我们介绍了 Dan Boneh 教授的背景,本节中我们来看看他如何评价嵌入式设备的安全问题。

嵌入式设备,如安全摄像头、数码相框、无线打印机和路由器,通常通过内置的 Web 界面进行配置。由于资源限制,这些设备无法运行完整的 Web 应用栈(如 LAMP),因此厂商需要自行开发轻量级应用。然而,构建安全的 Web 应用并非易事。

以下是 Dan Boneh 团队的研究发现:

  • 他们购买了约 20 种不同的嵌入式设备。
  • 逐一检查了这些设备上的 Web 应用。
  • 结果发现,这些设备普遍存在各种安全漏洞。

你可能会认为,一个数码相框被黑客攻击无关紧要。但事实并非如此。如果企业员工将此类设备接入公司网络,它就可能成为攻击者入侵整个企业网络的跳板。攻击者通常采用“跳板”策略,先控制一台设备,再横向移动,逐步渗透以获取核心数据或管理员权限。

上一节我们讨论了嵌入式设备的风险,本节中我们来看看从斯诺登事件中应吸取的安全教训。

基于斯诺登事件的启示,Dan Boneh 给出了两条核心建议。

建议零:绝不自行设计或实现密码算法
你应该使用现有的、经过充分验证的标准和开源实现。自行实现极易引入漏洞,例如不良随机数或侧信道攻击。

第一条建议:确保系统具备“密码敏捷性”
这意味着系统在设计之初就应支持多种密码算法。如果某个算法日后被发现存在漏洞,你只需切换配置即可启用新算法,而无需耗时数月紧急重构和部署。这在客户端-服务器模型中虽然更具挑战,但至关重要。一个常见的例子是软件更新机制,许多公司将其签名算法硬编码为 RSA,这缺乏敏捷性。

第二条建议:在构建 SSL/TLS 服务器时,优先使用支持前向保密的密钥交换机制
标准的 RSA 密钥交换机制存在一个问题:假设攻击者今天截获了加密的预主密钥,一年后他们若窃取了服务器的 RSA 私钥,就能解密之前截获的所有通信。这被称为缺乏前向保密性

而基于迪菲-赫尔曼(DHE)或椭圆曲线迪菲-赫尔曼(ECDHE)的机制则能提供前向保密。在此机制中,服务器的 RSA 密钥仅用于对 DH 交换消息进行签名认证,而非直接加密会话密钥。因此,即使 RSA 私钥在未来被盗,也无法解密过去被截获的通信会话。前向保密性是一个非常重要的安全属性。

上一节我们探讨了具体的安全建议,本节中我们来看看 Dan Boneh 教授为学生推荐了哪些课程。

随着网络应用日益重要,安全知识变得不可或缺。Dan Boneh 推荐了两门核心课程:

CS155:计算机与网络安全

  • 这门课程旨在培养学生建立“安全思维模式”。
  • 教学方式包括学习各种攻击技术,因为只有了解攻击,才能更好地进行防御。
  • 课程涵盖安全编程原则,如纵深防御最小权限原则
  • 该课程在春季学期开设,由 Dan Boneh 和 John Mitchell 共同授课。

CS255:密码学导论

  • 如果你对密码学的工作原理更感兴趣,这门课非常适合。
  • 掌握密码学知识能使你在未来的工作中,成为公司处理相关问题的核心人员。
  • 这是一门有趣且实用的课程。

本节课中我们一起学习了 Dan Boneh 教授关于安全领域的见解:从嵌入式设备的普遍漏洞,到斯诺登事件后应遵循的“密码敏捷性”和“前向保密”原则,最后了解了为深入该领域应学习的核心课程。安全是计算机系统中一个持续存在且日益重要的挑战。

课程 P143:安全与开放性的探讨 🛡️➡️🔓

在本节课中,我们将与克林顿政府时期美国联邦通信委员会(FCC)主席里德·亨特进行对话,探讨通信行业在20世纪90年代的巨大变革、政府监管的角色,以及当前关于数据隐私和政府监控的热点议题。我们将了解FCC的职责,回顾互联网商业化初期的关键决策,并深入讨论安全与开放性之间的*衡。


FCC的职责与独立性 🏛️

上一节我们介绍了课程背景,本节中我们来看看美国联邦通信委员会(FCC)的基本情况。FCC是美国的一个独立监管机构。

以下是关于FCC的几个关键点:

  • FCC由五名委员领导,其中一人担任主席。里德·亨特在1993年被比尔·克林顿任命为主席。
  • 该机构独立于行政部门,这意味着总统不能命令FCC做什么。
  • 它的权力来自立法机构,但一旦获得授权,其监管行为只受法院的制衡。公司或个人可以质疑其法规的合法性或合宪性。
  • 与许多其他国家不同,美国的通信技术行业基本没有政府所有权,FCC是该领域最强大的监管机构。

20世纪90年代的通信革命与FCC的角色 📡💻

了解了FCC的定位后,我们来看看它在那个激动人心的变革年代扮演了什么角色。20世纪90年代是通信发展的激动人心时期,发生了《电信法案》出台、互联网爆炸式增长、频谱拍卖开始等一系列快速变化。

当时,两位关键人物向时任FCC主席的里德·亨特提出了重要见解:

  1. “尼葛洛庞帝切换”:MIT媒体实验室的尼古拉斯·尼葛洛庞帝提出,通信的一切都是“反向”的。他认为,应该让所有语音通信通过空中(无线)进行,而所有数据通信通过地面物理网络进行。FCC的角色是改变法规,使企业能够执行这一重大切换。
  2. “这是一场战争”:英特尔CEO安迪·格鲁夫指出,分组交换数据是电路交换通信的颠覆性敌人。依赖模拟通信和电路交换技术的企业将被历史淘汰,政府不应试图拯救它们,而应为胜利的技术铺*道路。

FCC和美国科技及通信行业成功地执行了历史上最大规模的商业转型之一,例如整个贝尔网络从固定线路语音电话网络转变为空中移动通信网络。未能执行这些转变的企业成为了巨大的失败者,例如AT&T的市场价值在不到十年内萎缩了十分之九。

政府监管与互联网发展 🤔

上一节我们回顾了FCC在推动技术变革中的角色,本节中我们探讨政府是否应该干预互联网的治理与发展。这涉及到水*与垂直以及开放与封闭两种模式的讨论。

水*与垂直模式

  • 水*模式:指行业按层级水*组织,例如芯片层(英特尔)、操作系统层、应用层,各层由不同公司负责,层间合作以交付最终产品。
  • 垂直模式:以苹果公司为例,它从底层到顶层几乎包办一切,不对他人开放。

政府不应该指令市场采用哪种结构,而应让不同商业模型的公司自由竞争。

开放与封闭的含义

  1. 商业模型层面:例如,微软操作系统并非真正开放,需要许可才能为其设计应用。政府不应干预此类商业模型的开放与否。
  2. 垄断瓶颈层面:例如,谷歌在搜索市场占据80-90%的份额,构成了垄断,其搜索算法是封闭且保密的。当这种垄断权力被用于扼杀创新或竞争时,政府就应该介入。

从CALEA到现代监控议题 🕵️♂️📞

讨论了互联网的治理模式后,我们转向更*期的隐私与安全议题。早在1994年,美国国会就通过了《通信协助执法法案》(CALEA),旨在帮助执法部门对数字电话网络进行监控。

当时,语音通信主要通过固定线路网络进行,集中在少数几家受FCC监管的公司。政府可以相对容易地要求这些公司协助监听通话。当时的争论焦点主要是是否需要法院授权以及由谁支付监听费用

时至今日,情况已大不相同。政府感兴趣的不再只是语音通信,而是“越顶”公司(如谷歌、Facebook)收集的所有其他数据:位置、推特内容、电子邮件、照片等,用于预测个人行为。

关于设备制造商(如思科、华为)是否被要求在产品中预留“后门”以方便监听:

  • 在美国,没有法律或法规要求路由器、服务器或数据中心的设计必须允许后门。
  • 这个问题需要按国家来审视,例如在中国,这个问题存在大量辩论。

当前的关键问题在于,少数几家总部位于美国的公司收集并存储了海量的“越顶”信息,政府正试图获取这些数据。这引出了一个核心问题:既然谷歌能利用数据预测用户的广告偏好,国家安全机构为什么不能利用类似数据预测潜在不法分子的行为呢?

安全、信任与国际影响 🔐🌍

随着监控议题的发酵,网络安全和国际信任也受到挑战。一个具体领域是,有指控称美国国家安全局(NSA)影响了数据加密标准,使其更容易被政府破解。

这引发了人们对网络和互联网用于安全通信(如银行、电子商务)的信任危机。技术行业尚未能在网络的任何层面设计并实施令所有人满意的安全方案。这个问题若不能通过公私协商一致的方式解决,互联网的未来将受到影响。

关于美国被指控监听德国总理默克尔等国际盟友的事件,其国际影响备受关注。里德·亨特指出,当权者试图了解其他当权者的动向,这并非新鲜事。他认为,真正的议题并非简单的隐私与安全之争,而是公开与保密公共与秘密之间的*衡。

他引用已故参议员丹尼尔·帕特里克·莫伊尼汉的著作《保密》中的观点,认为政府所做的几乎所有目前保密的事情,实际上都应该公开(并非指实时推特直播,而是指政府应更开放地说明其行为)。自由的真正敌人是保密。提高透明度将有助于公众(例如美国公民)就安全的适当界限和隐私的适当权利形成共识。

迈向更开放与透明的未来 🚀

那么,如何才能达到更大的开放性和透明度呢?里德·亨特提出了几点建议:

以下是实现更大透明度可以采取的几项措施:

  • 大幅减少涉密人员:在美国,有超过一百万人拥有安全许可,这本身就削弱了保密的价值。应几乎无人能接触NSA计算机得出的关于不法分子的结论。
  • 限制涉密人员任期:这些人员的任期不应超过五年,以防止个人通过掌握秘密而对政府及私营部门产生过大影响力。
  • 公开信息收集的类别:政府收集信息的性质(总体类别,而非具体细节)应当公开,让每个人了解政府在做什么。
  • 保障被指控者的访问权:任何被政府盯上的个人,如果被指控或起诉,需要能够访问政府用于针对他们的信息。否则就成了由计算机和算法进行的审判。

他对当前的辩论能推动社会向这个方向前进感到乐观,认为*几个月的新闻报道极大地促进了这场本该公开的辩论。


本节课中,我们一起学习了FCC在通信变革中的关键作用,探讨了政府监管与互联网发展的复杂关系,回顾了从CALEA到现代大规模监控的演变,并深入思考了在安全需求下如何保障开放、透明与隐私权利。这场持续的辩论对于塑造数字时代的未来至关重要。

课程 P15:IPv4地址判断练习解析 🧩

在本节课中,我们将学习如何判断两个IPv4地址是否属于同一个网络。我们将通过分析一个具体的练习题,来掌握使用子网掩码进行“按位与”运算的核心方法。


上一节我们介绍了判断网络归属的基本概念,本节中我们来看看如何应用这些概念解决具体问题。

问题一解析

第一组地址是 102.134.0.1102.135.0.1,子网掩码为 255.255.0.0

两个地址在第二个八位组(即点分十进制中的第二段)不同,分别是134和135。将每个地址与子网掩码进行二进制“按位与”运算,可以计算出它们的网络地址。

以下是计算过程的核心公式:
网络地址 = IP地址 & 子网掩码

对于 102.134.0.1
102.134.0.1 & 255.255.0.0 = 102.134.0.0

对于 102.135.0.1
102.135.0.1 & 255.255.0.0 = 102.135.0.0

得到的网络地址 102.134.0.0102.135.0.0 并不相同。

结论:否,它们在不同的网络上。


问题二解析

上一问题展示了如何判断不同网络,现在我们来分析一个属于同一网络的例子。

第二组地址是 10.0.1.110.0.1.2,子网掩码为 255.255.255.0

同样,我们将两个地址分别与子网掩码进行“按位与”运算。

对于 10.0.1.1
10.0.1.1 & 255.255.255.0 = 10.0.1.0

对于 10.0.1.2
10.0.1.2 & 255.255.255.0 = 10.0.1.0

两种情况下,计算得到的网络地址都是 10.0.1.0

结论:是,它们在同一个网络上。


问题三解析

接下来我们看一个因第三个八位组不同而导致网络不同的情况。

第三组地址是 10.0.1.1(源)和 10.0.2.1(目的),子网掩码为 255.255.255.0

计算网络地址:

  • 源地址 10.0.1.1 的网络地址为 10.0.1.0
  • 目的地址 10.0.2.1 的网络地址为 10.0.2.0

结论:否,它们不在同一个网络上。源地址在网络 10.0.1.0,目的地址在网络 10.0.2.0


问题四解析

现在我们来分析一个使用不同子网掩码的例子。

第四组地址是 171.64.15.32(源)和 171.64.15.64(目的),子网掩码为 255.255.255.192

计算网络地址:

  • 源地址 171.64.15.32 的网络地址为 171.64.15.0
  • 目的地址 171.64.15.64 的网络地址为 171.64.15.64

结论:否,它们不在同一个网络上。


问题五解析

最后,我们来看一个地址部分匹配但网络不同的情况。

第五组地址是 171.64.15.32171.65.14.33,子网掩码为 255.255.0.0

计算网络地址:

  • 第一个地址的网络地址为 171.64.0.0
  • 第二个地址的网络地址为 171.65.0.0

虽然两个地址的第一个八位组(171)相同,但计算出的完整网络地址并不相同。

结论:否,它们不在同一个网络上。


课程总结 📝

本节课中我们一起学习了判断两个IPv4地址是否属于同一网络的方法。核心步骤是:将IP地址与子网掩码进行“按位与”运算,比较得到的网络地址是否完全相同

我们通过五个练习题巩固了这一方法:

  1. 第二段不同导致网络不同。
  2. 主机位不同,网络地址相同。
  3. 第三段不同导致网络不同。
  4. 使用更精细的子网掩码划分出不同子网。
  5. 仅部分字段匹配不足以判定为同一网络。

掌握这一技能是理解IP网络通信和子网划分的基础。

课程 P16:IPv4 地址详解 🌐

在本节课中,我们将要学习 IPv4 地址的分类、结构以及它们是如何演变成今天所使用的 CIDR 格式的。我们还会了解地址的分配机制。


原始的 IPv4 地址分类

最初的 IP 地址被分成了三个类别:A类B类C类。每个类别都将 IP 地址分成两部分:网络部分主机部分

  • 网络部分:表示一个管理域,例如 MIT、BBN 或斯坦福大学。
  • 主机部分:表示该网络上的具体设备。

以下是各类地址的具体划分:

  • A类地址:网络部分有 7 位,可以表示 128 个网络。主机部分有 24 位,因此一个 A 类网络可以容纳约 1600 万台计算机。
    • 公式2^7 = 128 个网络,2^24 = 16,777,216 台主机。
  • B类地址:网络部分有 14 位,主机部分有 16 位。因此一个 B 类网络可以容纳 65,536 台计算机。
    • 公式2^16 = 65,536 台主机。
  • C类地址:网络部分有 21 位,主机部分有 8 位。因此一个 C 类网络可以容纳 256 台计算机。
    • 公式2^8 = 256 台主机。


分类地址的局限性

上一节我们介绍了 A、B、C 三类地址的简单划分。本节中我们来看看这种分类方式在实践中遇到的问题。

A、B、C 类的划分方式虽然简单,但很快被发现不够灵活。例如,无论是 MIT 还是斯坦福大学,都曾获得最早的 A 类地址之一。这意味着它们各自被分配了超过 1600 万个地址的地址块。

而 MIT 可能为其宿舍分配一个相当于 B 类的地址块,为几百人分配了 65,536 个地址。在 IP 地址资源丰富的早期,这不是问题。但随着互联网的普及和使用量激增,我们需要更精细、更高效的地址分配策略。

有用的提示:在 1999 年,斯坦福大学交还了其 A 类地址块,而 MIT 至今仍保留着它。


CIDR:无类别域间路由

为了解决分类地址的僵化问题,IPv4 地址通过 CIDR(无类别域间路由) 进行了重新结构化。

与之前只有固定的 8位、16位 或 24位 网络前缀不同,CIDR 允许使用任意长度的前缀。这意味着所有 CIDR 前缀都定义了一个地址块,其大小是 2 的幂次方。

当我们谈论 CIDR 地址时,我们使用“斜线记法”来表示其网络掩码,例如 /16/20

以下是 CIDR 地址块的示例:

  • 一个 /16 的 CIDR 块:表示网络前缀长度为 16 位。这个块描述了 2^(32-16) = 2^16 = 65,536 个地址。
  • 一个 /20 的 CIDR 块:表示网络前缀长度为 20 位。这个块描述了 2^(32-20) = 2^12 = 4,096 个地址。

CIDR 块是当今地址被结构化和管理的标准方式。例如,斯坦福大学拥有一个 /16 的地址块,大约包含 65,536 个地址。


IPv4 地址的分配与管理

那么,IPv4 地址是如何分配和管理的呢?这由一个名为 IANA(互联网号码分配局) 的组织负责,它是互联网名称与数字地址分配机构(ICANN)的一部分。

IANA 将工作委托给区域互联网注册管理机构(RIR)。每个大洲都有自己的 RIR,例如:

  • 美洲的 RIR 是 ARIN
  • 亚太地区的 RIR 是 APNIC

这些 RIR 有各自的政策,负责将大的地址块分解为更小的块,并分配给需要它们的组织。

你可能在新闻中读到“我们耗尽了 IPv4 地址”。这并不完全准确。今天仍有很多未使用的地址。实际情况是,IANA 在 2011 年将其 IPv4 地址池中最后可分配的 /8 地址块分配给了各个 RIR。自那以后,地址的管理和分配责任就转移到了 RIR 层面。

扩展阅读:关于地址耗尽引发的经济和技术复杂性,约翰·彼得森(时任互联网架构委员会成员)在斯坦福大学进行过一次精彩演讲。本课程不要求掌握这部分材料,但强烈推荐。你应该能在相关网站上找到这个演讲。


总结与路由决策

本节课中我们一起学习了 IPv4 地址的结构、从分类到 CIDR 的演变,以及它们如何被分配。

最后,主机如何做出其首次路由跳转决策呢?那就是判断一个数据包是应该发送到本地网络节点,还是应该发送到由 CIDR 块 定义的网关路由器。地址块的大小由前缀长度定义:前缀越短(如 /8),地址块越大;前缀越长(如 /24),地址块越小

课程P17:最长前缀匹配 (LPM) 🧭

在本节课中,我们将学习互联网路由器如何决定数据包的转发方向。核心内容是最长前缀匹配算法,这是现代路由器做出转发决策的基础。


路由器转发决策概述 🌐

互联网路由器通常连接多条链路,因此需要为接收到的数据包选择一条链路进行转发。这个过程发生在数据包从源到目的地的每一跳中。

上一节我们介绍了路由器转发的基本场景,本节中我们来看看路由器具体如何做出这个决定。

转发表的作用 📋

路由器通过查询一个称为转发表的数据结构来做出转发决策。转发表由一系列条目组成,每个条目包含一个部分IP地址(即一个网络前缀)和一个对应的输出链路。

以下是转发表条目的一个示例:

  • 第一条目:171.33.xx.xx -> 链路5
  • 第二条目:xx.xx.xx.xx -> 链路1 (默认路由)

在条目中,x 代表通配符。例如,171.33.xx.xx 意味着IP地址的前两个字节(16位)必须是 171.33,后两个字节可以是任意值。

当数据包到达时,路由器会检查其目的IP地址,并找出转发表中最匹配(即最具体)的条目,然后将数据包转发到该条目关联的链路上。

理解最长前缀匹配 (LPM) 🔍

最长前缀匹配,或称LPM,是IP路由器用于决定数据包转发路径的核心算法。

每个路由器的转发表条目通常包含两部分:

  1. 一个描述地址块的CIDR条目(例如 171.33.0.0/16)。
  2. 对于匹配该CIDR条目的数据包的下一跳地址。

一个IP地址可能同时匹配转发表中的多个条目。例如,考虑右侧的转发表:

  • 条目A: 0.0.0.0/0 -> 链路1 (默认路由)
  • 条目B: 171.33.0.0/16 -> 链路5

目的地为 171.33.5.245 的数据包会同时匹配条目A(0位前缀)和条目B(16位前缀)。根据LPM规则,路由器会选择前缀更长的条目B,因为它更具体,并将数据包通过链路5转发。

其核心逻辑可以用以下伪代码描述:

def longest_prefix_match(packet_dest_ip, forwarding_table):
    best_match = None
    for entry in forwarding_table:
        if packet_dest_ip in entry.network_prefix:
            if best_match is None or entry.prefix_len > best_match.prefix_len:
                best_match = entry
    return best_match.output_link

示例解析 📝

让我们回到课程开始时那个使用通配符x的转发表例子。

如果我们将该转发表表示为标准的CIDR条目,它将如下所示。在这个简单例子中,所有前缀长度都是8位的倍数(即按字节对齐)。

以下是CIDR格式的转发表:

  • 171.33.xx.xx 变为 171.33.0.0/16
  • xx.xx.xx.xx 变为 0.0.0.0/0 (默认路由)

通过这种表示,LPM的原则就更加清晰了:对于任何前往 171.33.x.x 网络的数据包,/16 的前缀比 /0 的默认路由前缀更长、更精确,因此会被优先选用。


总结 📚

本节课中我们一起学习了路由器转发决策的关键——最长前缀匹配 (LPM) 算法。我们了解到路由器通过查询转发表,并选择与数据包目的IP地址匹配的、前缀长度最长的条目来决定转发路径。这条规则确保了数据包总能被导向最具体的、最精确的路由路径。理解LPM是理解互联网路由基础的重要一步。

计算机网络课程 P18:最长前缀匹配 (LPM) 🧩

在本节课中,我们将要学习路由器转发数据包时使用的一种关键技术——最长前缀匹配。我们将了解其工作原理,并通过一个具体例子来掌握如何应用它。


上一节我们介绍了路由表的基本概念。本节中我们来看看路由器如何根据目标IP地址,在路由表中找到最合适的转发路径。

路由器在转发数据包时,会查看数据包的目标IP地址,并将其与路由表中的条目进行比对。路由表中的条目通常包含一个网络前缀(或称为子网地址)和一个对应的输出接口。路由器需要找到与目标IP地址匹配的条目,并将数据包从该条目指定的接口发送出去。

当存在多个匹配的条目时,路由器遵循一个核心原则:选择具有最长匹配前缀的条目。这就是“最长前缀匹配”。


核心概念与规则

最长前缀匹配的规则可以总结为以下步骤:

  1. 将数据包的目标IP地址与路由表中每个条目的网络前缀进行比较。
  2. 找出所有网络前缀是目标IP地址前缀的条目(即匹配的条目)。
  3. 从所有匹配的条目中,选择网络前缀最长的那个条目
  4. 按照该条目指示的接口转发数据包。

以下是判断一个前缀是否匹配的简单方法:

如果(目标IP地址 & 子网掩码) == 网络前缀,则匹配。

其中 & 表示按位与运算。


实例解析

现在,我们通过一个具体例子来应用上述规则。假设路由器中有以下转发表(路由表):

目标网络(前缀) 接口
10.1.1.0/24 A
10.1.0.0/16 B
10.0.0.0/8 C
0.0.0.0/0 D

注意/24/16/8 表示子网掩码中“1”的位数,分别对应掩码 255.255.255.0255.255.0.0255.0.0.00.0.0.0/0 是默认路由,匹配任何地址。

问题:一个目标地址为 10.1.1.1 的数据包到达,路由器应通过哪个接口转发?

让我们一步步分析:

  1. 列出所有匹配的条目

    • 10.1.1.0/24 比较:10.1.1.1 的前24位(10.1.1)与该前缀一致,匹配
    • 10.1.0.0/16 比较:10.1.1.1 的前16位(10.1)与该前缀一致,匹配
    • 10.0.0.0/8 比较:10.1.1.1 的前8位(10)与该前缀一致,匹配
    • 0.0.0.0/0 比较:匹配任何地址,匹配
  2. 应用最长前缀匹配规则
    在以上四个匹配的条目中,我们需要比较它们前缀的长度。

    • 10.1.1.0/24 的前缀长度是 24 位。
    • 10.1.0.0/16 的前缀长度是 16 位。
    • 10.0.0.0/8 的前缀长度是 8 位。
    • 0.0.0.0/0 的前缀长度是 0 位。

    其中,前缀长度最长的是 24 位,对应的条目是 10.1.1.0/24

  3. 得出结论
    因此,路由器将选择 10.1.1.0/24 这条路由,并通过其指定的接口 A 转发该数据包。


本节课中我们一起学习了最长前缀匹配的原理和应用。我们了解到,当路由表中有多个条目与目标IP地址匹配时,路由器会选择网络前缀最长的那一条,因为这代表了最精确、最具体的路由路径。通过实例练习,我们掌握了从匹配的条目中筛选出最长前缀的具体步骤。这是确保互联网数据包能够高效、准确送达目的地的关键机制之一。

计算机网络课程 P19:最长前缀匹配 (LPM) 详解 🧩

在本节课中,我们将学习路由器转发数据包时的一个核心决策过程——最长前缀匹配。我们将通过具体的例子,理解路由器如何从多个可能的路由条目中,为给定的目标IP地址选择最精确的下一跳路径。


概述 📋

当路由器收到一个需要转发的数据包时,它会检查数据包的目标IP地址,并将其与路由表中的条目进行比对。路由表中的条目通常由网络前缀(如 63.195.0.0/16)和对应的出接口组成。如果目标地址同时匹配多个前缀,路由器将遵循 “最长前缀匹配” 原则,即选择前缀长度最长的那个条目进行转发。这是因为更长的前缀意味着更具体的网络范围,路由决策也就更精确。

上一节我们介绍了路由表的基本结构,本节中我们来看看最长前缀匹配原则是如何具体应用的。


案例分析 🔍

假设我们有一个包含以下条目的路由表:

  1. 默认路由:0.0.0.0/0 -> 链接 1
  2. 前缀 A:63.195.0.0/16 -> 链接 2
  3. 前缀 B:63.195.3.0/30 -> 链接 3
  4. 前缀 C:171.0.0.0/10 -> 链接 4
  5. 前缀 D:171.0.0.0/24 -> (不匹配当前任何目标地址)

现在,我们将为不同的目标IP地址确定其转发路径。

案例一:目标地址 63.195.3.2

这个地址匹配两个前缀:默认路由 (0.0.0.0/0) 和前缀 B (63.195.3.0/30)。

  • 默认路由的前缀长度是 0位
  • 前缀 B (63.195.3.0/30) 的前缀长度是 30位

最长前缀匹配原则:选择前缀长度更长的条目。
因此,63.195.3.0/30(30位)比默认路由(0位)更长,路由器会选择链接3

核心逻辑可以用伪代码表示

if destination_ip matches 63.195.3.0/30:
    use link 3
elif destination_ip matches 63.195.0.0/16:
    use link 2
else:
    use default route (link 1)


案例二:目标地址 171.55.0.0

这个地址匹配三个条目:默认路由、前缀 C (171.0.0.0/10) 和前缀 D (171.0.0.0/24)。我们需要逐一检查:

  1. 匹配默认路由 (0.0.0.0/0):总是匹配。
  2. 匹配前缀 C (171.0.0.0/10):地址 171.55.0.0 的前10位与 171.0.0.0 的前10位相同,因此匹配。
  3. 不匹配前缀 D (171.0.0.0/24):地址 171.55.0.0 的第二个八位组是 55,而前缀 D 要求第二个八位组是 0,因此不匹配。

在匹配的条目中(默认路由和前綴 C),前缀 C 的长度为 10位,比默认路由的 0位 更长。
所以,根据最长前缀匹配原则,路由器会将数据包发送到链接4


案例三:目标地址 63.195.32.0

这个地址的匹配情况如下:

  • 匹配默认路由:总是匹配。
  • 不匹配前缀 A (63.195.0.0/16):虽然前16位 (63.195) 相同,但前缀 A 定义的是一个 /16 的网络。地址 63.195.32.0 的第三个八位组是 32,而前缀 63.195.0.0/16 包含从 63.195.0.063.195.255.255 的所有地址,因此它是匹配的。这里原描述有误,实际上它匹配前缀A。
  • 不匹配前缀 B (63.195.3.0/30):前30位不同,不匹配。

因此,匹配的条目是默认路由和前缀 A (63.195.0.0/16)。前缀 A 的长度为 16位,比默认路由更长。
所以,路由器会选择链接2


案例四:目标地址 44.99.23.1171.1.28.160

对于这两个地址,我们快速应用上述原则:

  • 44.99.23.1:它只匹配默认路由 (0.0.0.0/0),因此答案是链接1
  • 171.1.28.160:它匹配默认路由和前綴 C (171.0.0.0/10)。
    • 不匹配前缀 D (171.0.0.0/24),因为其第二个八位组是 1 而不是 0
    • 在匹配的条目中,前缀 C (171.0.0.0/10) 是更长的前缀(10位 > 0位)。
    • 因此,路由器会选择链接4

总结 🎯

本节课中我们一起学习了最长前缀匹配 (LPM) 这一路由器核心转发规则。关键要点如下:

  • 核心原则:当目标IP地址匹配路由表中多个条目时,路由器选择网络前缀长度最长的条目进行转发。
  • 原因:更长的前缀代表更小的、更具体的网络范围,能提供更精确的路由。
  • 决策流程:路由器从匹配的条目中,简单比较其前缀长度(即 / 后面的数字),数字最大的即为最终选择。

理解最长前缀匹配,是掌握IP路由和数据包转发机制的基础。

计算机网络课程 P2:应用程序的一天 🌐

在本节课中,我们将学习网络应用程序如何工作。我们将探讨网络连接的基本模型,并分析三个现代应用程序(万维网、BitTorrent 和 Skype)如何利用这种连接来实现各自的功能。理解这些基础概念是学习更复杂网络原理的第一步。


网络应用程序的力量 💪

网络应用程序的力量在于,你可以有多台计算机,每台都有自己的私人数据,每台可能由不同的人拥有和控制,交换信息。与您的本地应用程序不同,这些应用程序只能访问位于本地系统的数据。网络应用程序可以跨越世界交换数据。

例如,想象使用Web浏览器阅读杂志。服务器由出版商运行,具有其中包含所有杂志文章,并且可能还包括过去的所有期数。随着文章的更正或添加,你可以立即看到更新的版本和新的内容。整个文章目录可能太大,无法下载,所以你可以按需加载。如果没有网络,那么你需要某人发送DVD或USB,只关注最新的一期。

基本通信模型:可靠的双向字节流 🔄

所以基本模型是您有两个计算机,每个运行本地程序,并且这两个程序通过网络通信。最常用的通信模型是双向可靠的字节流

程序A运行在计算机A上可以写入数据,这些数据通过网络发送,这样程序B运行在计算机B上就可以读取它。同样,程序B可以写入数据,程序A可以读取。还有其他的通信模式,我们在课程中稍后会讨论。但双向可靠的字节流是网络今天最常用的模式之一。

让我们走一遍看看这个是什么。计算机B在右边正在等待其他计算机连接到它。计算机A在左边想要与B通信。例如,尽管在这里被绘制为服务器,它也可以是运行Web浏览器的移动电话。A和B现在设置连接。

当A向连接写入数据时,这个数据通过网络传输,并且B可以以类似的方式读取它。如果B向连接写入数据,那个数据也会通过网络传输,并且A可以读取它。任何一方都可以关闭连接。例如,当Web浏览器从Web服务器请求完数据时,它可以关闭连接。同样,如果服务器想要,它也可以关闭连接。如果你在网页浏览器中见过错误消息,说连接重置由对端,这就是什么意思。当网页浏览器没有预期时,网页服务器关闭了连接。当然,服务器也可以拒绝连接。你可能见过连接拒绝的消息,或者让浏览器等待很长时间,因为服务器甚至没有以拒绝的形式回应。


应用示例一:万维网 🌍

现在我们已经看到了网络应用程序基本通信的方式,让我们来看看我们的第一个例子:万维网。万维网使用被称为HTTP的东西,它代表超文本传输协议。当你在浏览器中看到 http://,那意味着它正在使用HTTP进行通信。我们将更深入地研究HTTP的细节稍后,在课程中。我们现在将覆盖的应用程序,我只是会在HTTP中提供一个非常高级别的概述。

客户端打开与服务器的连接并向其发送命令。最常见的命令是 GET,它请求一个页面。HTTP被设计为一种以文档为中心的方式,使程序能够通信。

例如,如果我输入 http://www.stanford.edu 在浏览器中,浏览器连接到服务器 www.stanford.edu,并向网站的根页面发送 GET 请求。服务器接收请求,检查其是否有效,用户可以访问该页面并发送响应。响应与其相关的数字代码相关联。例如,如果服务器对 GET 发送 200 OK 响应,这意味着请求被接受。其余响应包含文档数据。在 www.stanford.edu 网页的示例中,一个 200 OK 的反应将包括描述主要斯坦福页面的超文本。

其他要求类型如 PUTDELETE,以及其他要求响应如 400,这意味着可能有一个坏请求,可能是格式错误。因为HTTP是文档中心的,客户端请求命名一个文件。HTTP全部使用ASCII文本,它是人类可读的。

例如,获取斯坦福请求的开始看起来像这样:

GET / HTTP/1.1
Host: www.stanford.edu

对成功请求的回应开始看起来像这样:

HTTP/1.1 200 OK
Content-Type: text/html
...

基本模型很简单的客户端,客户端通过写入连接发送请求,服务器读取此请求,处理它,并在连接中写入响应。然后,客户端阅读这些。


应用示例二:BitTorrent 🌊

让我们看第二个应用:BitTorrent。BitTorrent是一个程序,允许人们分享和交换大文件。与Web不同,在BitTorrent中,客户端从不同的服务器请求文档。客户端从其他客户端请求文档,以便单个客户端可以从许多其他客户端并行请求。

BitTorrent将文件分解为数据块,称为片段。当客户端从其他客户端下载完整的片段时,它会告诉其他客户端它已经有了那个片段,所以它们可以下载到这些协作的客户端集合中。这些集合被称为蜂群。所以我们讨论一个客户端加入或离开蜂群。

BitTorrent使用与世界 wide web相同的机制:一个可靠的双向字节流。但它以稍微更复杂的方式使用它。

以下是BitTorrent下载文件的基本步骤:

  1. 当客户端想要下载一个文件时,它首先必须找到被称为种子文件的东西。通常你通过世界 wide web找到这个,并使用HTTP下载它。
  2. 种子文件描述了你想要下载的数据文件的一些信息,也告诉BitTorrent关于那个种子的跟踪器的信息。跟踪器是一个节点,它跟踪那个种子,因此加入种子的蜂群成员的客户端被称为什么。
  3. 你的客户通过HTTP再次联系跟踪器,以请求其他客户端的列表。
  4. 你的客户打开对这些其他客户端的一些连接,并开始请求文件的片段。这些客户端反过来也可以自己请求片段。
  5. 此外,当一个新的客户加入蜂群时,跟踪器可能会告诉这个新的客户连接到你的客户。

因此,而不是一个客户端和服务器之间的单个连接,您有一个客户端之间的密集连接图,动态交换数据。


应用示例三:Skype 📞

让我们看看Skype,流行的语音、聊天和视频服务。Skype的专有系统,在2008年没有关于其内部工作方式的官方文档。哥伦比亚的一些研究人员主要通过查看,以及Skype客户端发送消息的时间和地点。消息被加密,尽管他们在2011年无法查看内部。但是,一个主题的灌木丛消失了,反向工程了协议并发布了开源代码,所以现在我们对协议在最简单模式下的工作有了更好的理解。

当你想要呼叫某人在Skype时,它是一个简单的客户端服务器交换,有点像HTTP。作为呼叫者,你打开与接收者的连接。如果接收者接受你的呼叫,你开始交换语音、视频或聊天数据。但是,与网页不同,在Skype的情况下,你没有客户端和服务器,你只有两个客户端。因此,而不是让个人电脑从专门的服务器请求东西,你有两个个人电脑在互相请求数据。这一差异最终对Skype的工作方式产生了极大的影响。

困难来自于一个叫做NAT或网络地址转换的东西。NAT今天处处可见。一个小型家庭无线路由器是一个应用。当手机连接到互联网时,它被一个应用保护。我们将在课程的后期详细讨论他们。但是,你现在只需要知道,如果你位于NAT后面,那么你就可以向外部互联网建立连接。但是,互联网上的其他节点很难轻易地向你建立连接。

在这个例子中,这意味着客户端B可以自由地向其他节点建立连接。但是,其他节点很难向客户端B建立连接。这就是这个红色绿色渐变的含义。来自绿色侧的连接工作正常,但是,来自红色侧的连接却不行。

所以,这里的复杂性在于,如果客户端A想要呼叫客户端B,它无法建立连接。它无法通过Skype,需要绕过这个问题。它这样做,使用被称为会晤服务器的东西。当你登录Skype,你的客户打开连接到控制服务器网络的连接。在这种情况下,客户端B打开连接到会晤服务器的连接。这工作得很好,因为服务器不在NAT后面,因此客户端B可以打开连接没有任何问题。

当客户端A呼叫客户端B,它向约会服务器发送消息。由于服务器已与客户端B建立开放连接,它告诉B有呼叫请求。在客户端B上弹出一个呼叫对话。如果客户端B接受呼叫,然后它为客户端A打开连接。客户端A正在尝试为客户端B打开连接,但由于B在网络后面,它不能。相反,它向连接客户端B的计算机发送消息,然后要求客户端B为客户端A打开连接。由于客户端A不在网络后面,这个连接可以正常打开。这个被称为反向连接,因为它逆转了启动连接的预期方向。客户端A正在尝试连接客户端B,但相反,客户端B为客户端A打开连接。

这在Skype中发生,因为Skype客户端通常是个人机器。公共可访问的Web服务器通常不在NAT后面。由于您想要服务器被互联网上的每个人都访问,将其放在NAT后面是一个坏主意。因此,连接到Web服务器的过程很容易。个人电脑,然而,它们通常因为安全和其他原因而在后面。因此,Skype必须集成一些新的通信模式来绕过它们。

所以,如果两个客户端都在后面,我们不能反转连接。客户端A无法连接到客户端B,并且客户端B无法连接到客户端A。为了处理这个案例,Skype引入了一种第二种类型的服务器叫做中继站。中继站不能在NAT后面。如果两个客户端都在后面,然后他们通过中继站进行通信。他们都为中继站打开连接。当客户端A发送数据时,中继站通过客户端B打开的连接将其转发给B。当客户端B发送数据时,中继站将数据转发给客户端A。


总结 📝

本节课中我们一起学习了网络应用程序的基础。我们看到了网络应用中最常见的通信模型之一:可靠的双向字节流。这允许在两台不同计算机上运行的程序交换数据。它抽象掉了整个网络到一个简单的读写关系。

尽管这是一个非常简单的通信模型,但它可以用于非常创新和复杂的方式。我们看了三个例子:世界 wide web、BitTorrent和Skype。

  • 世界 wide web 是一个客户端服务器模型。客户端打开与服务器的连接并请求文档,服务器响应文档。
  • BitTorrent 是一种点对点模型。其中一群客户端相互建立连接并交换数据片段,形成密集的网络连接。
  • Skype 是两者的混合体。当Skype客户端可以直接通信时,它们以点对点的方式进行通信。但有时客户端无法直接建立连接,因此,他们会通过会晤服务器或中继服务器进行通信。

你可以看到,看似非常简单的抽象——双向可靠的字节流——可以在许多有趣的方式中使用。通过改变程序如何建立连接以及不同程序做什么,我们可以创建从文档检索到蜂群下载到IP电话的复杂应用。在BitTorrent中,IP电话跟踪者的角色与客户端有很大的不同,例如,它们拥有不同的数据和角色。

网络协议基础 P20:地址解析协议 (ARP) 🔍

在本节课中,我们将要学习地址解析协议(ARP)。ARP是网络层用于发现链路层地址的机制。它解决了设备在发送IP数据包时,如何确定目标链路层地址的问题。

协议层与地址

上一节我们介绍了网络分层的基本概念,本节中我们来看看不同协议层地址的区别。

每个协议层都有其自己的名称和地址。IP地址是网络层地址,它描述一个主机在网络层中的唯一目的地。相比之下,链路层地址描述特定的网络接口卡(NIC),它是一个在链路层发送和接收帧的唯一设备。

例如,以太网地址是一个48位(6字节)的地址,通常写作由冒号分隔的六个十六进制数,如 00:13:04:72:02:04。当你购买以太网卡时,它已经被预先配置了一个唯一的以太网地址。

所以,IP地址标识“这台主机”,而以太网地址标识“这张以太网卡”。

地址的耦合与解耦

虽然链路层和网络层地址在协议层的分配和管理上是完全解耦的,但在实际应用中,它们并非毫无关联。

一个主机通常具有多个IP地址,每个接口一个。这涉及到子网掩码的概念。例如,在一个典型的网络设置中,网关路由器有多个接口,每个接口都有自己的链路层地址(标识网卡)和网络层地址(标识该接口在网络中的位置)。

左侧接口的IP地址可能是 192.168.0.1,右侧接口的IP地址可能是 171.43.228.1。这种逻辑上解耦但在实践中耦合的情况,部分是由于历史原因:互联网需要能在各种已有的链路层技术上运行。

ARP解决的问题

现在,我们来看看ARP具体要解决什么问题。

假设节点A(IP: 192.168.0.5)想要发送一个IP数据包给节点B(IP: 171.43.228.5)。A检查目标地址,发现B不在同一子网内(通过子网掩码 255.255.255.0 判断)。因此,A需要将数据包发送给网关(IP: 192.168.0.1)。

于是,A构造的IP包:

  • 网络层目标地址171.43.228.5 (B)
  • 网络层源地址192.168.0.5 (A)

但是,为了在链路上传输,这个IP包必须封装在一个链路层帧中。A需要知道网关 192.168.0.1 对应的链路层地址(如MAC地址),才能正确填写帧头。

ARP就是为了解决这个“如何将网络层IP地址映射到链路层MAC地址”的问题而设计的。

ARP协议工作原理

ARP是一个简单的请求-回复协议。每个节点都维护一个ARP缓存,用于存储IP地址到MAC地址的映射。

以下是ARP的基本工作流程:

  1. 检查缓存:当节点需要向某个IP地址发送数据时,首先检查自己的ARP缓存中是否有该IP的映射。
  2. 发送ARP请求:如果缓存中没有映射,节点会构造一个ARP请求包。这个包的主要内容是:“谁的IP地址是 X.X.X.X?请告诉 Y.Y.Y.Y(我的IP)”。
  3. 广播请求:节点将这个ARP请求包封装在链路层帧中,目的MAC地址设置为广播地址(如 FF:FF:FF:FF:FF:FF)。这样,同一局域网内的所有设备都会收到这个请求。
  4. 处理请求:所有收到广播的节点都会查看请求中的“目标IP地址”字段。如果与自己的IP不匹配,则忽略该请求,但可以顺便将发送者的IP和MAC地址记录到自己的ARP缓存中(这是一种优化)。
  5. 发送ARP回复:只有IP地址匹配的节点(即被询问的节点)会构造一个ARP回复包。包的内容是:“我的IP地址是 X.X.X.X,我的MAC地址是 AA:BB:CC:DD:EE:FF”。
  6. 单播回复:该节点将这个回复包单播发送给请求者(使用请求包中提供的请求者MAC地址)。
  7. 更新缓存并发送数据:请求者收到回复后,将IP到MAC的映射存入自己的ARP缓存。随后,它就可以使用这个MAC地址来封装链路层帧,并发送之前等待的数据包。

ARP缓存中的条目不是永久有效的,它们有一个生存时间(TTL),超时后会被删除。这确保了当网络设备更换或地址变更时,映射信息能够更新。

ARP数据包格式

为了更好地理解ARP,我们来看看ARP数据包的格式。一个ARP包包含以下字段:

  • 硬件类型:指明链路层类型,如以太网(值为1)。
  • 协议类型:指明要映射的网络层协议地址类型,如IP(值为 0x0800)。
  • 硬件地址长度:指明MAC地址的长度(单位:字节),以太网为6。
  • 协议地址长度:指明网络层地址的长度(单位:字节),IPv4为4。
  • 操作码:指明是ARP请求(1)还是ARP回复(2)。
  • 发送方MAC地址:发送者的链路层地址。
  • 发送方IP地址:发送者的网络层地址。
  • 目标MAC地址:在请求中,此字段通常填充为0;在回复中,是请求者的MAC地址。
  • 目标IP地址:要查询或回复的IP地址。

所有字段都按网络字节序(大端序)存储。

示例:ARP请求包关键字段

操作码: 1 (请求)
发送方MAC: 68:A8:60:58:52:22
发送方IP: 192.168.0.5
目标MAC: 00:00:00:00:00:00 (填充0)
目标IP: 192.168.0.1

示例:ARP回复包关键字段

操作码: 2 (回复)
发送方MAC: 01:8E:7F:3C:E1:1A
发送方IP: 192.168.0.1
目标MAC: 68:A8:60:58:52:22
目标IP: 192.168.0.5

总结

本节课中我们一起学习了地址解析协议(ARP)

我们了解到,为了在不同网络层之间传递数据,需要将网络层的IP地址映射到链路层的MAC地址。ARP通过一个简单的广播请求、单播回复的机制,动态地发现和维护这种映射关系。每个设备维护的ARP缓存提高了效率,避免了每次通信都要进行ARP查询。

ARP是局域网通信的基础协议,它使得IP数据包能够被正确地封装在链路层帧中,从而到达下一跳设备或最终目的地。

课程 P21:互联网与IP协议回顾 🌐

在本节课中,我们将回顾互联网的基本工作原理、其四层模型以及核心的架构原则。我们将学习应用程序如何使用互联网,以及IP协议在其中扮演的关键角色。

概述

本单元介绍了互联网工作的基本知识,包括网页浏览和Skype等应用程序的工作原理,以及互联网的基本结构。

互联网的四层模型

上一节我们介绍了本单元的学习目标,本节中我们来看看互联网的核心架构模型。

你应该已经熟悉了互联网的四层模型。互联网被分解为四个独立的层次。

以下是各层的主要职责:

  • 每一层负责特定的功能。
  • 各层协同工作以实现数据传输。

理解互联网为何以这种方式工作,以及为什么分层设计是所有网络(不仅仅是互联网)中的好主意,比了解它们如何工作更为重要。

数据包与封装原则

你已经看到,互联网通过将数据分解成称为数据包的小单位来工作。

当你请求一个网页时,你的计算机会向Web服务器发送一些数据包。互联网负责决定这些数据片段如何到达正确的目的地,以及Web服务器响应的、包含网页内容的数据包如何正确返回给你。

两种架构原则——分层和分组——在封装原则中结合在一起。封装是上层如何利用下层的数据包服务。

封装的过程可以简化为:上层数据包 + 本层头部信息 = 新的数据包

这种方式使得每一层对数据包的使用都独立于其他层,保持了架构的清晰和简单。我们将在未来的单元中讨论更多架构原则。

本单元核心主题回顾

具体来说,我们在本单元中学习了四个主要主题。

1. 应用程序如何使用互联网

菲尔解释了Skype、BitTorrent和Web浏览器等各种不同应用程序都以极其相似的方式使用互联网。

你学到大多数应用程序都希望通过可靠的方式进行通信,即建立“两个或多个端点之间的双向字节流”。

2. 互联网的结构:四层模型

你学习了互联网的四层模型,以及每一层负责的职责。

你也会理解我们为什么使用互联网协议。每次我们在互联网上发送数据包时都会用到它。IP协议被称为互联网的“细腰”,因为它是最关键、最通用的一层。

3. 互联网协议详解

因为IP如此重要,我们花了几个视频来解释IP的作用及其工作原理。

我们目前讨论的是IP版本四,因为它是当今使用最广泛的版本。你已经学习了IP地址的格式,以及路由器如何根据IP地址进行查找和转发。

稍后我们将学习IP的新版本——IP版本六

4. 基本架构思想与原则

你学习了网络的三个基本原则,它们都与我们对互联网的理解密切相关。

以下是这三个核心原则:

  • 分组交换:数据被分解为自包含的数据包进行传输。这些包含信息的包在路由器之间基于包头中的信息逐跳转发。
  • 分层:将复杂系统划分为多个功能层,每层提供特定服务,并利用下层的服务。
  • 封装:这是将上层的数据包放入下层数据包“数据”部分的过程。这有助于在各层之间清晰地分离关注点,明确数据在层次结构中是如何被处理的。

总结

本节课中,我们一起学习了互联网的基本结构,并理解了分组交换、分层和封装这三种基本的架构理念。

你现在应该对互联网的基本结构有了良好的理解,知道了你的网页浏览器如何工作,以及互联网如何在两台计算机之间传递数据包。你现在知道了TCP和IP是什么,以及它们之间的关系。

这些知识可能看起来像是底层的技术细节,但它们实际上是互联网每年得以建立和发展的基石。新的互联网应用和用途不断涌现,但几乎所有应用都使用你正在学习的基本原理,并且几乎都基于TCP/IP协议族。

从这些始终如一的、强大的基本原理开始学习,你将掌握持续重要的知识。即使我们转向5G无线网络或物联网时代的“互联网3.0”,互联网令人兴奋的部分在于其能力总是在扩大和变化,但有一些核心理念和原则是永恒不变的。

通过学习它们,你不仅是在学习互联网今天如何工作,更是在理解所有网络通信的基石。

课程 P22:传输层简介 🚀

在本节课中,我们将深入研究计算机网络中的传输层。传输层为应用程序之间的数据通信提供服务。我们将了解两种主要的传输协议:UDP和TCP,并探讨它们的工作原理、核心算法以及一个重要的网络设计原则——端到端原则。


传输层的作用

上一节我们介绍了课程概述,本节中我们来看看传输层的核心作用。

传输层位于网络层之上,为运行在不同主机上的应用进程提供逻辑通信服务。其核心是为应用程序提供两种主要的数据通信模式:

  • 在UDP的情况下,提供简单的、不可靠的数据包交付服务。
  • 在TCP的情况下,提供可靠的、双向的字节流传输服务。

本单元学习目标

在了解了传输层的基本定位后,本节我们将明确本单元的具体学习内容。

本单元将围绕传输层展开,旨在让你掌握以下知识和技能:

  • 学习传输层(特别是TCP和UDP)的工作原理、抽象模型及其核心算法。
  • 学习一个名为“端到端原则”的重要网络设计原则,该原则指导我们如何以及在何处正确地实现功能。
  • 回答一系列关键问题,例如:
    • TCP如何精确地建立连接?
    • TCP报文段的具体结构是什么?
    • 如何使两台计算机实现高性能的可靠数据传输?
    • TCP如何知晓数据是否在传输过程中受损?

核心技术与方法

为了深入理解上述目标,我们需要掌握一些核心的技术工具和方法。以下是本单元将涉及的关键技术点:

  • 错误检测算法:你将学习使用三种不同的算法来检测数据传输中的错误。

    1. 校验和
    2. 循环冗余检查
    3. 消息认证码
  • 协议设计工具:你将学习网络协议设计的基本工具和方法。

    • 有限状态机:我们将详细解释状态机的概念,并具体分析TCP如何利用状态机来管理连接。

学习成果展望

掌握了这些核心概念后,我们能达到什么程度呢?本节我们来展望本单元的学习成果。

在本单元结束时,你将能够:

  • 完全理解TCP如何可靠地传输数据。
  • 透彻掌握TCP如何通过建立连接来实现可靠传输。
  • 理解TCP协议如何设计以正确、相对高效地运行(其实现极致高性能的机制将在后续单元中探讨)。

总结

本节课中,我们一起学习了传输层的基本介绍。我们明确了传输层为应用层提供通信服务的核心角色,区分了UDP和TCP两种服务模式。我们列出了本单元将要深入探讨的关键问题,包括连接管理、可靠传输和错误检测等。此外,我们还预告了将要学习的核心工具,如错误检测算法和有限状态机。通过本单元的学习,你将为深入理解TCP/IP网络的核心——传输层——打下坚实的基础。

计算机网络课程 P23:TCP 服务模型详解 🧩

在本节课中,我们将要学习传输控制协议(TCP)的核心服务模型。TCP是互联网上超过95%应用所使用的传输层协议,因为它为应用程序提供了可靠的、双向的字节流通信服务。


TCP 概述与角色

TCP是传输层协议的一个典型例子。当一个应用程序使用TCP时,它会将数据字节交给TCP层。TCP层将这些字节封装成TCP段,然后交给下层的IP协议处理。

IP层将TCP段封装成IP数据包,添加IP地址。接着,数据包被交给链路层,链路层构建链路帧(例如以太网帧),添加链路地址(如MAC地址),最后通过物理介质(如网线)发送出去。

当两个应用程序使用TCP通信时,它们会在两端建立一个双向的通信通道,我们称之为TCP连接。TCP通过一个状态机来跟踪和管理连接的状态。


TCP 连接的建立与拆除

三次握手建立连接

TCP连接通过三次握手过程建立,以确保双方都准备好通信。

  1. SYN:主机A向主机B发送一个SYN(同步)报文,表示希望建立连接,并告知A方字节流的初始序列号(例如从1000开始)。
  2. SYN-ACK:主机B回复一个SYN-ACK报文。ACK部分确认收到了A的SYN请求,SYN部分表示B也希望建立反向连接,并告知B方字节流的初始序列号。
  3. ACK:主机A最后发送一个ACK报文,确认B的SYN请求。至此,双向连接建立完成。

公式表示握手过程

A -> B: SYN (Seq=A_ISN)
B -> A: SYN-ACK (Ack=A_ISN+1, Seq=B_ISN)
A -> B: ACK (Ack=B_ISN+1)

数据传输

连接建立后,应用程序可以将数据视为连续的字节流交给TCP。TCP负责将字节流分割成段,确保其可靠、有序地送达对端。即使网络状况不佳,TCP也能通过重传等机制保证数据正确到达。

四次挥手拆除连接

当通信结束时,需要通过四次挥手来优雅地关闭连接。

  1. FIN:主机A发送FIN(结束)报文,表示A没有更多数据要发送了。
  2. ACK:主机B回复ACK,确认A的FIN请求。此时,A到B的数据流关闭,但B到A的通道仍可传输数据。
  3. FIN:当主机B也没有数据要发送时,它向A发送自己的FIN报文。
  4. ACK:主机A回复最后的ACK,确认B的FIN。连接完全关闭,双方释放资源。


TCP 提供的核心服务

上一节我们介绍了连接的生命周期,本节中我们来看看TCP具体为应用程序提供了哪些关键服务。以下是TCP服务与实现机制的总结:

  • 可靠的字节流交付:确保数据按顺序、无差错地从一端送达另一端。
  • 按序交付:即使网络导致数据包乱序到达,TCP也能根据序列号重新排序后交给应用。

为了实现可靠性,TCP采用了以下四种核心机制:

  1. 确认与重传:接收方收到数据后,会发送确认(ACK)。发送方在一定时间内未收到ACK,则会重传数据。
  2. 校验和:每个TCP头部都包含一个校验和,用于检测数据在传输过程中是否损坏。
    // 校验和计算覆盖TCP头部和数据
    checksum = calculate_checksum(tcp_header, data);
    
  3. 序列号:每个字节在流中都有唯一序列号,用于检测数据丢失、重复和乱序
    // 假设初始序列号(ISN)为1000,段携带500字节
    segment1.seq = 1000; // 第一个字节序号
    segment2.seq = 1500; // 下一个段的起始序号
    
  4. 流量控制:接收方通过通告窗口大小来告知发送方自己还能接收多少数据,防止发送过快导致接收方缓冲区溢出。

此外,TCP还为整个网络提供拥塞控制服务,通过动态调整发送速率来避免网络过载,公*地共享网络带宽。


TCP 报文段头部详解

TCP头部比IP和以太网头部更复杂,因为它需要携带更多信息来管理可靠的连接。你不需要记住所有细节,但应了解关键字段的作用。

以下是TCP头部中最重要的字段摘要:

  • 源端口与目的端口:各16位。目的端口标识接收主机上的目标应用程序(如Web服务常用80端口)。源端口由发起连接的主机随机选择,用于标识本地的发送进程。两者共同在多任务环境中区分不同连接。
  • 序列号:32位。指出本报文段所发送数据的第一个字节在整个字节流中的序号
  • 确认号:32位。期望收到对方下一个报文段的第一个数据字节的序号。同时表示该序号之前的所有数据已正确接收。
  • 头部长度:4位。指示TCP头部有多少个32位字(即长度),因为头部有可变的选项字段。
  • 标志位:共6位,用于控制连接状态。
    • ACK:确认号字段有效。
    • SYN:用于发起连接,同步序列号。
    • FIN:用于释放连接。
    • PSH:提示接收方应立即将数据交付给上层应用,而不是缓存。
  • 窗口大小:16位。用于流量控制,指示从确认号开始,接收方还能接收的字节数。
  • 校验和:16位。用于校验头部和数据部分,确保完整性。

一个TCP连接在互联网上由五个要素唯一标识,称为五元组

(源IP地址, 源端口, 目的IP地址, 目的端口, 传输层协议(TCP))


总结

本节课中我们一起学习了TCP服务模型的核心内容。

我们首先了解了TCP在协议栈中的角色,以及它如何通过三次握手建立可靠连接,并通过四次挥手拆除连接。接着,我们深入探讨了TCP为应用程序提供的可靠字节流按序交付服务,并分析了实现这些服务的四大机制:确认与重传、校验和、序列号以及流量控制。此外,TCP还通过拥塞控制服务于整个网络的健康。

最后,我们解析了TCP报文段头部的关键字段,如端口号、序列号、确认号和标志位,并理解了如何用五元组在全球唯一标识一个TCP连接。

掌握TCP的基本服务模型是理解现代网络通信的基石,在接下来的课程中,我们将继续学习TCP更高级的特性,如滑动窗口和拥塞控制算法。

计算机网络课程 P24:UDP服务模型详解 🧩

在本节课中,我们将学习传输层的第二个重要协议——用户数据报协议(UDP)。我们将了解UDP的简单服务模型、其报文结构、工作原理以及它适用的应用场景。


概述

UDP(用户数据报协议)由那些不需要TCP所提供的保证交付服务的应用程序使用。这些应用程序可能以私有方式处理重传,或者根本不需要可靠的交付。UDP比TCP简单得多,它主要完成一项核心任务:将应用程序数据封装成UDP数据报,然后交给网络层进行传输。


UDP的简单性

上一节我们提到了UDP的定位,本节中我们来看看它为何如此简单。UDP数据包仅标识出数据应该发送到的目标应用程序。

在传输过程中,UDP数据报被封装在IP数据包的数据字段中。UDP提供的服务非常简单,这从其头部字段数量极少就能看出来。与拥有超过十个头部字段的TCP不同,UDP头部只有四个字段。


UDP头部字段解析

以下是UDP头部的四个核心字段及其作用:

  • 源端口:指示数据来自哪个应用程序。如果远端需要回复,它将使用此端口号作为目的端口,以便数据能正确返回到源主机上的对应应用。
  • 目的端口:指示数据应该交付给目标主机上的哪个应用程序。UDP中的端口号在功能上与TCP相同,用于将传入的数据包定向到正确的应用程序进程。
  • 长度:这是一个16位字段,指定整个UDP数据报(头部+数据)的长度,单位为字节。其值必须至少为8字节,因为这是UDP头部本身的固定长度。
    • 公式UDP总长度 = 8字节(头部) + 数据长度
  • 校验和:用于检测UDP数据报在传输过程中是否出错。当使用IPv4时,UDP校验和是可选的。如果发送方不计算校验和,则该字段填充为全零。如果使用,校验和的计算范围不仅包括UDP头部和数据,实际上还包含了IP头部的一部分信息(源IP地址、目的IP地址和协议号)。
    • 代码示意(计算范围)校验和计算数据 = 伪IP头部(源IP、目的IP、协议号) + UDP头部 + UDP数据

你可能会疑惑,为什么UDP校验和要包含IP头部的一部分信息?这难道不违反网络分层原则吗?确实如此。这样做的合理性在于,它允许UDP层检测那些被错误路由、发送到错误目的地的数据包。

总的来说,UDP头部小巧,因为它为应用程序提供的服务非常简单:它提供了一种简单的消息传递机制,用于从一台主机的应用程序发送数据,而远程主机上的应用程序可能收到,也可能收不到这些数据。


UDP的工作方式:多路复用与分用

UDP端口的工作方式与TCP端口相同。我们可以通过一个例子来理解其多路复用与分用过程:

假设主机A上的进程1(使用端口177)想要发送数据给主机B上的进程1。进程1将数据放入一个新的UDP数据包,并将目的端口设置为177。主机A会添加自己的源端口号,以便任何回复都能被正确送回。然后,该UDP数据包被封装进IP数据包,发送至主机B。主机B收到后,移除IP封装,根据UDP头中的目的端口号177,将数据定向交付给进程1。

因此,我们可以将UDP看作一种简单的多路复用/分用机制。它将来自主机A上不同进程的数据复用到一个输出流中,并在主机B端将到达的UDP数据包流分用,交付给正确的目标进程。事实上,有些人将UDP戏称为“用户分路协议”,这本质上概括了UDP的核心功能。


UDP服务模型的三大属性

总结UDP的服务模型,它具有以下三个核心属性:

  1. 无连接的数据报服务:通信前无需建立连接,所有必要信息都包含在单个数据报中。这也意味着数据包可能以任何顺序到达。
  2. 不可靠的交付服务:UDP不向发送方发送确认(ACK),不提供数据是否到达的反馈,也没有检测丢失数据包的机制。如果数据包在途中丢失,UDP不会通知应用程序,也不会要求源端重传。
  3. 无拥塞控制:UDP本身不包含调节发送速率的拥塞控制机制。

UDP的服务听起来非常像IP层提供的服务。这是因为UDP在IP服务的基础上,仅仅增加了一个简单的封装以及将数据定向到正确应用程序的能力(即端口机制)。


为什么需要UDP?—— 应用场景

既然UDP如此简单,甚至不可靠,我们为什么还需要它?UDP被用于那些不需要或不想要可靠交付服务的应用程序。以下是其主要应用场景:

  • 简单的请求-响应应用

    • DNS(域名系统):用于将主机名转换为IP地址。查询和响应通常完全包含在一个UDP数据包内。无需建立连接,轻量且快速。如果请求失败(超时),应用层会直接重发查询。
    • DHCP(动态主机配置协议):出于类似原因使用UDP。
    • NTP(网络时间协议):也是基于请求-响应模式。
  • 有特殊自定义需求的实时应用

    • 一些应用程序使用UDP,是因为它们对重传、拥塞控制和顺序交付有特殊需求,希望自己在应用层实现这些逻辑。例如,早期的网络文件系统(NFS) 就在UDP之上构建了自己的重传机制。
    • 一些实时流媒体音频和视频服务也曾使用UDP,以降低延迟并避免TCP重传和拥塞控制带来的抖动。不过,如今大多数基于HTTP的流媒体已转向使用TCP。


总结

本节课中,我们一起学习了用户数据报协议(UDP)。我们了解到UDP是一种极其简单的传输层协议,它提供无连接、不可靠的数据报交付服务。其核心功能是通过端口号实现应用进程间的多路复用与分用。UDP的简洁性使其非常适合简单的请求-响应应用(如DNS、DHCP)以及那些需要在应用层自定义可靠性或实时性策略的场景。

课程 P25:ICMP 服务模型 🛠️

在本节课中,我们将学习互联网控制报文协议(ICMP)的服务模型。ICMP 是网络层的一个重要辅助工具,用于报告错误和诊断网络问题。虽然 IP 协议本身不保证数据包的可靠交付,但 ICMP 提供了关键的反馈机制,帮助我们了解网络状况。

上一节我们介绍了互联网协议(IP)和路由表,它们是网络层数据转发的基础。本节中,我们来看看 ICMP 如何帮助端主机和路由器之间通信网络层信息,从而诊断问题并报告错误。

ICMP 概述与工作原理

ICMP 运行在网络层之上,严格来说属于传输层协议。当终端主机或路由器需要报告错误时,它会将相关信息放入 ICMP 报文的有效载荷中,然后将其封装在 IP 数据报中发送出去。

以下是 ICMP 报文生成的基本过程:

  1. 当路由器或主机需要发送 ICMP 错误报告时,它会截取触发该报告的原始 IP 数据包的头部
  2. 同时,它还会截取该原始 IP 数据包有效载荷的前 8 个字节
  3. 这些信息(原始 IP 头 + 前 8 字节数据)被放入一个新的 ICMP 报文中。
  4. 该 ICMP 报文被封装在一个新的 IP 数据包中,其源地址是报告者(路由器),目的地址是原始数据包的发送者。

这个过程可以用以下伪代码描述:

# 当路由器R需要发送ICMP错误报告时
def generate_icmp_error(original_packet):
    icmp_payload = original_packet.header + original_packet.data[:8]  # 原始IP头 + 前8字节数据
    icmp_message = ICMP(type=ERROR_TYPE, code=ERROR_CODE, payload=icmp_payload)
    new_ip_packet = IP(src=R, dst=original_packet.src, data=icmp_message)
    send(new_ip_packet)

常见的 ICMP 消息类型

ICMP 定义了多种消息类型来报告不同的网络状况。以下是六个最常用的消息类型示例,你无需记忆具体编号,但需要了解其含义:

  • 目的地不可达 (Type 3):当路由器无法将数据包送达最终网络或主机时发送。
    • 代码 0: 网络不可达:路由器在转发表中找不到目标网络。
    • 代码 1: 主机不可达:数据包到达了目标网络,但最后一个路由器找不到目标主机。
    • 代码 3: 端口不可达:数据包到达了目标主机,但主机上没有应用程序在监听目标端口。

  • 回显请求/应答 (Type 8/Type 0):用于 ping 工具,测试主机之间的连通性。
    • Type 8, Code 0: 回显请求。
    • Type 0, Code 0: 回显应答。

  • 超时 (Type 11, Code 0):当 IP 数据包的生存时间(TTL)字段减为 0 时,路由器会丢弃该包并发送此消息。这是 traceroute 工具的核心机制。

实用工具:Ping 与 Traceroute

ICMP 最常见的应用体现在两个网络诊断工具上:pingtraceroute

Ping:测试连通性 🎯

ping 命令用于测试与另一台主机的连通性和响应时间。其工作原理非常简单:

  1. 源主机(A)向目标主机(B)发送一个 ICMP 回显请求 报文。
  2. 如果网络通畅且 B 在线,B 在收到请求后会回复一个 ICMP 回显应答 报文。
  3. A 通过计算发送请求和收到应答的时间差,得到往返延迟。

你可以在命令行中尝试:

ping www.example.com

Traceroute:追踪路径 🗺️

traceroute 命令用于发现数据包从源主机到目标主机所经过的路径(路由器),并测量到每一跳的延迟。它巧妙地利用了 IP 数据包的 TTL 字段 和 ICMP 的 超时 消息。

以下是 traceroute 的工作步骤:

  1. 首先,源主机发送一个 UDP 数据包(或 ICMP 回显请求),并将其 IP 头中的 TTL 设置为 1
  2. 第一个路由器收到后,将 TTL 减为 0,于是丢弃该包,并向源主机发送一个 ICMP 超时 报告。源主机由此得知第一个路由器的地址和到它的往返时间。
  3. 接着,源主机发送 TTL=2 的数据包。该包到达第一个路由器后 TTL 减为 1,被转发到第二个路由器。第二个路由器将其 TTL 减为 0 后丢弃,并发送 ICMP 超时报告。源主机得知第二个路由器。
  4. 此过程重复,每次 TTL 加 1,直到数据包到达目标主机。
  5. 当数据包到达目标主机时,traceroute 通常会使用一个目标主机上未开放的高端口号。目标主机因此会回复一个 ICMP 端口不可达 消息,这标志着追踪完成。

你可以在命令行中尝试:

traceroute www.example.com

总结

本节课中我们一起学习了 ICMP 服务模型。ICMP 作为 IP 协议的辅助协议,在网络层之上运行,为核心的网络层功能提供错误报告和诊断支持。我们了解了其基本工作原理,认识了常见的消息类型,并深入剖析了 pingtraceroute 这两个依赖 ICMP 的经典网络工具是如何工作的。掌握 ICMP 有助于我们更好地理解和排查网络问题。

课程 P26:端到端原则详解 🧩

在本节课中,我们将学习互联网架构中的一个核心设计理念——端到端原则。我们将探讨其两种不同的表述,理解其背后的逻辑,并通过具体例子说明它如何影响网络协议与应用的设计。

端到端原则在互联网设计中占据特殊位置,因为它实际上指代两个不同的原则。第一个原则涉及正确性:如果在设计网络系统时不遵循端到端原则,那么系统很可能存在缺陷并可能传输错误数据。第二个原则被称为“强端到端原则”,它比第一个更广泛和通用。

一个简单的文件传输例子 📁

上一节我们介绍了端到端原则的基本概念,本节中我们通过一个具体的文件传输例子来理解网络的角色。

假设我们需要将文件从计算机A传输到计算机B。应用程序在A和B之间建立一个连接,它从计算机A读取文件并将其写入TCP连接。计算机B则从套接字中读取数据并将其写入本地文件。在这个过程中,网络本身做得非常少,它仅仅是将数据包从A转发到B。A和B负责建立连接,应用程序负责读取和写入数据。

那么,为什么网络不多做一些工作来帮助提升性能呢?实际上,网络可以做很多事情来使文件传输更快、更便捷。

以下是网络可以提供的几种“帮助”:

  • 网络可以自动压缩A和B之间的数据包。如果文件是纯英文文本,这可能会将传输大小减少十倍。
  • 网络可以重新格式化或合并请求。假设A想要传输两个文件,网络可以将其合并为一个传输请求。
  • 网络可以进行缓存。如果文件已经存储在离B更*的计算机C上,网络可以从C而不是A传输文件。
  • 网络可以自动添加安全性,例如加密数据,以防止被恶意方读取。
  • 网络可以添加移动性支持,使得设备在网络中移动时,数据包能继续正确路由。

如果网络为我们实现了这些功能,我们的应用程序就无需再关心这些问题。但总体而言,网络为什么不这样做呢?

端到端原则的核心论点 🎯

上一节我们看到了网络可能提供的诸多“帮助”,本节中我们来看看反对在网络内部实现这些功能的核心理由——端到端原则。

原因在于端到端原则。该原则由Saltzer、Reed和Clark在1984年的一篇论文中首次描述。他们阐述的端到端原则如下:

只有在通信系统端点的应用的知识和帮助下,才能完全和正确地实现某项功能。因此,将该功能作为通信系统本身的特性来提供是不可能的(有时,通信系统提供的该功能的不完整版本可能有助于提升性能)。

我们称这种推理方式为端到端论证。换句话说,网络或许能做很多事情来提供帮助,但它只能提供辅助。如果系统要正常工作,那么端点需要负责确保功能的正确实现,因为只有端点拥有完成此事所必需的全部信息。网络可以帮助你,但你不能依赖它。

例如,如果你想确保应用程序是安全的,你需要在应用程序内部实现端到端的安全。网络可能会添加额外的安全措施,但端到端的安全只能由应用程序本身来正确完成。因此,将安全作为网络的特性,以便应用程序不必担心它,是不可能的。

通过实例深入理解 🔍

上一节我们介绍了端到端原则的正式定义,本节我们通过几个具体实例来加深理解。

让我们回到在两台计算机之间传输文件的例子。Clark和Reed在阐述端到端论点时指出:“你想要确保文件完整无损地到达”。文件数据将在源和目的地之间的多台计算机中传递。从源A到目的地B的路径可能经过计算机C、D、E。从A到C、C到D、D到E、E到B的每一段链路都有错误检测功能。如果在传输过程中一个数据包被损坏,接收方可以检测到并拒绝这个包,发送方将通过TCP确认等机制发现包未成功到达并重新发送。

现在,有人可能会说:既然链路层有错误检测,数据包在任何链路上都不会被损坏,那么它完全不会被损坏。因此,如果它成功到达目的地,文件就已经成功传输。麻省理工学院的一些程序员正是这样想的,由于网络提供了错误检测,他们假设网络将检测所有问题。这个假设被证明是错误的,由于这个错误,开发者最终丢失了大量源代码。

发生了什么?传输路径上的一台计算机(假设是计算机D)的内存发生了故障,以至于有时候一些比特位会被翻转。D会接收到数据包,检查它们并认为它们正确,然后将其移入主内存。就在这个过程中,数据被损坏了。D随后会转发数据包,但由于链路错误检测机制,从链路的角度看,数据包看起来正常,并且能通过每一次检查。链路错误检测是为传输中的错误设计的,而不是为存储中的错误设计的。

确保文件正确到达的唯一方法是进行端到端的检查。当源端发送文件时,它包含一些错误检测信息(如校验和或哈希)。当目的地重新组装文件时,它检查文件是否完整且无错误。这是确保正确性的唯一可靠方法。网络可以提供帮助,但它不能对正确性负责。

再举一个具体例子:想想TCP。TCP提供了一个可靠的字节流服务,但这种可靠性并非完美无缺。存在一种极小的可能性,TCP会将一些错误数据传递给你,例如因为TCP协议栈中存在bug,或者某个错误悄然出现。所以,虽然这种情况极不可能发生,但TCP确实可能传递被损坏的数据。因此,你需要对传输的数据进行端到端的检查。例如,BitTorrent在通过TCP传输文件块后,会使用哈希值来检查每个块是否成功且正确地到达。

性能增强与正确性保障 ⚖️

上一节我们强调了端到端检查对正确性的必要性,本节我们看看网络如何在遵守该原则的前提下提升性能。

让我们回到TCP和可靠性的问题。如果你想实现端到端的可靠数据传输,那么你需要一种像TCP这样的端到端可靠协议。但根据对端到端论点的深入理解,你必须通过端到端的功能来确保正确性。网络可以包含某个功能的“不完整版本”作为性能增强。

今天的无线链路层就提供了这种性能增强。有线链路层非常可靠(除非线缆或连接器损坏),但无线链路由于多种原因可靠性较低。通常,99.999%的有线链路数据包能成功到达下一跳,而无线链路的成功率可能只有50%或80%。结果,TCP在低可靠性链路上工作得不好。

因此,无线链路层通过在链路层进行重传来提高可靠性。当你的笔记本电脑向接入点发送数据包时,如果接入点成功接收,它会立即(几微秒后)发送一个链路层确认。如果笔记本电脑没有收到这个确认,它会重传数据包。这样做几次可以将链路的可靠性从80%提高到99%或更高,从而让TCP工作得更好。TCP本身将正常工作,它能在没有链路层帮助的情况下可靠传输数据,但链路层的帮助极大地提升了TCP的性能。

这就是端到端原则的正确应用方式:确保正确性的功能必须端到端地完成。你可以在中间节点做一些事情来帮助提升性能,但如果你不依赖端到端的机制来保证正确性,那么总有一天系统会出问题。

强端到端原则 💪

上一节我们讨论了网络作为性能增强者的角色,本节我们介绍一个更严格的原则变体。

存在一个版本的端到端原则,在IETF的RFC 1958(《互联网的架构原则》)中被描述,我们称之为“强端到端原则”。它指出:网络的工作是尽可能高效、灵活地传输数据包,其他所有功能都应该在网络的边缘(即端点)完成

这个强端到端原则比第一个更强。第一个原则说,你必须在边缘实现端到端的功能,但也可以在网络中间实现它以改进性能。而这个强原则说,不应该在中间实现,只应在边缘实现。

强原则的推理基于灵活性和简单性。如果网络实现了一个功能来尝试帮助端点,那么它是在对端点的行为做出假设。例如,当无线链路层使用重传来提高可靠性以便TCP更好工作时,它假设增加的重传延迟对于提升可靠性是值得的。但这并不总是正确的。除了TCP,还有其他协议可能并不那么看重可靠性,它们可能更愿意发送一个新的、不同的数据包,而不是重传旧的。但由于链路层内置了提高可靠性的机制,这些其他协议也被迫接受它,这成为了创新和进步的障碍。

随着网络层级的增加,各层开始添加优化,并假设其上层和下层的行为。在Wi-Fi的情况下,重新设计链路层变得越来越困难,因为它假设了网络层和传输层的某种行为。如果你发明了一种新的传输层或网络层协议,它很可能需要适应Wi-Fi的行为才能良好工作。这样,网络设计变得僵化和固化,从长期设计和网络演进的角度看,真的很难改变。

因此,强端到端论点在长期网络设计和演进方面极具价值。但在短期设计和性能优化方面,存在一种张力。网络工程师和运营商往往不遵循它,因此,随着时间的推移,网络性能虽然越来越好,但架构的灵活性可能受到损害。

总结 📝

本节课中,我们一起学习了互联网架构中的核心设计思想——端到端原则。我们首先了解到它包含两个层面:一是关于正确性的基本原则,指出确保功能正确实现的职责必须在通信端点;二是更强的原则,主张所有高级功能都应仅在网络边缘实现。

我们通过文件传输的例子,理解了网络为何应保持简单(仅负责转发数据包),而将复杂功能(如可靠性保障、安全性)留给端点应用。我们深入探讨了端到端检查的必要性,例如通过哈希校验确保文件完整,并区分了网络为提升性能(如无线链路层重传)而提供的“不完整”帮助与端点必须负责的“完整”正确性保障之间的区别。

最后,我们对比了基本原则与强原则,认识到强端到端原则在维护网络长期灵活性和鼓励创新方面的重要性,尽管在实践中它与短期性能优化存在一定张力。掌握端到端原则,是理解互联网为何如此设计以及如何构建健壮网络应用的关键。

课程 P27:错误检测算法详解 🛡️

在本节课中,我们将学习网络通信中用于确保数据完整性的三种核心错误检测算法:校验和、循环冗余校验(CRC)以及消息认证码(MAC)。我们将探讨它们的工作原理、优缺点以及各自适用的场景。

概述

网络和设备并非完美,在数据传输过程中可能引入错误。为了使网络能够正常运行,必须能够检测这些错误。例如,路径上的路由器可能因硬件故障而翻转数据包中的某些位。如果翻转的位恰好是信用卡交易金额的最高有效位,后果将非常严重。因此,我们需要能够检测到错误的发生,避免将损坏的数据当作正确数据接受。现代数据网络通常使用三种不同的错误检测算法:校验和、循环冗余校验(CRC)和消息认证码(MAC)。理解它们之间的差异至关重要,否则可能导致错误的协议决策或分析。

从高层次看,错误检测的过程如下:我们有一个数据包,在该数据上计算一些错误检测位,并将其附加或预置到数据包中。例如,以太网在数据包后附加一个CRC,而传输层安全协议(TLS)则在消息后附加一个MAC。IP协议则预先生成一个校验和,并将其放置在IP头部。

1. 校验和

校验和是三种算法中最简单的一种。其核心思想是将数据包中的所有数据相加。TCP和IP协议就使用了校验和。校验和的优点是计算速度快、成本低,即使在早期软件实现为主的时代也很有价值。然而,它的主要缺点是错误检测保证较弱。虽然它能捕获许多随机错误,但仅用两个位错误就可能“欺骗”校验和。如果这两个位错误相互抵消(例如,一个错误使数值增加3,另一个错误使其减少3),校验和将无法捕获这个错误。因此,校验和能捕获很多错误,但对能捕获哪些错误提供的保证非常弱。

校验和的计算方法

IP、UDP和TCP使用“一补码”校验和。这意味着它们使用一补码算术来累加数据包。算法步骤如下:

  1. 开始时,将数据包的校验和字段设置为零。
  2. 然后,将数据包的每个16位字相加。
  3. 每当累加和超过 2^16 - 1(即65535)时,将溢出的高位(进位)加回到低位。
    • 例如:60000 + 80000 = 140000,这超过了65535。计算 140000 - 65535 = 74465,然后将进位1加回去,得到 74465 + 1 = 74466
  4. 累加完整个数据包后,对最终的和进行按位取反(即翻转所有位)。
  5. 将取反后的值设置为数据包的校验和。
  6. 在接收端,将整个数据包(包括校验和字段)再次按同样规则累加。如果结果全为1(即 0xFFFF),则校验通过。

有一个边缘情况:如果计算出的校验和恰好是全1(0xFFFF),则不能将其设置为零,因为校验和字段为零表示“未使用校验和”。因此,在这种情况下,校验和字段仍应设置为全1。

以下是用C语言风格伪代码描述的简化过程:

uint16_t compute_checksum(char *data, int length) {
    uint32_t sum = 0;
    // 假设数据长度是16位(2字节)的整数倍
    for (int i = 0; i < length; i += 2) {
        sum += (data[i] << 8) | data[i+1]; // 组合成16位字
        if (sum & 0xFFFF0000) { // 检查是否有进位
            sum = (sum & 0xFFFF) + 1; // 将进位加回低位
        }
    }
    return ~(sum & 0xFFFF); // 取反得到校验和
}

考虑到早期互联网实现大多基于软件,这种简单快速的算法非常有帮助。但其缺点是不够健壮,虽然能检测许多随机错误,但能提供的保证很弱。在实践中,它只能保证捕获单个位错误。不过,由于链路层承担了主要的错误检测工作,校验和在实际中工作得相当好。

2. 循环冗余校验

上一节我们介绍了简单快速的校验和。本节中,我们来看看更健壮但也更复杂的循环冗余校验(CRC)。CRC在计算上比校验和昂贵得多,但也健壮得多。它的核心思想是计算一个多项式除以另一个固定“生成多项式”后的余数。以太网和许多链路层协议都使用CRC技术。TCP和IP之所以可以使用较弱的校验和,部分原因在于链路层已经使用了更强大的CRC。

如果一个CRC的长度为 c 位,那么它可以保证检测到:

  • 任何单个位错误。
  • 任何两个位错误。
  • 任何长度不超过 c 位的连续错误(即突发错误)。
  • 任何奇数个位错误。

因此,CRC比校验和提供了强大得多的错误检测保证。

CRC的工作原理

CRC将 n 位消息数据浓缩为 c 位错误检测数据(c < n)。例如,一个1500字节的以太网帧使用一个4字节(32位)的CRC。USB和蓝牙使用16位的CRC。当然,CRC无法检测所有错误。对于任意一个随机数据包,其CRC值与正确CRC值匹配的概率是 2^{-c}(即 1/(2^c))。例如,使用8位CRC时,在所有可能的数据包中,有 1/256(约0.4%)的包会拥有相同的CRC值。

CRC算法基于多项式运算。它将消息的每一位视为一个多项式的系数(位为1表示该项存在,位为0表示不存在)。例如,消息 11011101 对应的多项式是:
M(x) = x^7 + x^6 + x^4 + x^3 + x^2 + 1
(注意:最高位对应最高次项)。

CRC计算需要一个称为“生成多项式” G(x) 的固定值。例如,用于USB的CRC-16算法的生成多项式是:
G(x) = x^16 + x^15 + x^2 + 1
(通常写作 0x8005,省略了最高位的 x^16 系数1)。

计算CRC的步骤如下:

  1. 将原始消息 M(x) 左移 c 位(即在低位补 c 个0),得到新的多项式 M'(x)
  2. M'(x) 除以生成多项式 G(x)
  3. 得到的余数 R(x)(长度为 c 位)就是CRC值。
  4. 将CRC值附加到原始消息后面进行发送。
  5. 接收端将收到的“消息+CRC”作为一个整体,再次除以 G(x)。如果余数为0,则CRC校验通过。

这个过程可以通过硬件非常快速和高效地实现。CRC算法的强度取决于所选择的生成多项式 G(x)。对此已有大量研究,产生了许多具有良好错误检测特性的标准多项式。因此,在实践中应使用这些标准多项式,而不是自行设计。

链路层通常使用CRC,因为它们相当健壮。由于许多链路层对突发错误敏感,CRC的突发错误检测能力非常有用。硬件可以很容易地在数据包写入或读取过程中实时计算CRC。

3. 消息认证码

前面两节我们讨论了用于检测随机错误的校验和与CRC。本节我们来看第三种算法——消息认证码(MAC),它主要用于安全目的,但常被与错误检测混淆。MAC将数据包与一个秘密密钥结合来生成一个值。理论上,只有拥有该秘密密钥的人才能生成或验证MAC。

如果你收到一个数据包且其MAC正确,那么你可以相当确信该数据包来自拥有密钥的另一方(或是一个重放的数据包)。除非攻击者拥有密钥,否则生成一个具有正确MAC的新数据包异常困难。实际上,如果MAC算法足够强大,那么给定一个数据包及其MAC,攻击者对于MAC值看起来是什么样子一无所知。因此,MAC能够抵抗恶意篡改。

MAC在传输层安全协议(TLS)中被广泛使用,也就是当你通过HTTPS安全浏览网页时所用的技术。然而,MAC并不擅长检测非恶意的随机错误。如果我在数据包中翻转一个位,更改后的数据包拥有相同MAC的概率并非零。我看到很多人在谈论错误纠正时犯这个错误,认为MAC和CRC一样好。事实并非如此。

  • 如果我有一个16位的CRC,我保证能检测到任何长度≤16位的突发错误。
  • 如果我有一个16位的MAC,我只能以很高的概率(例如 1 - 1/65536)检测到篡改。这个概率很高,但考虑到网络传输的海量数据包,失效的可能性仍然存在。

MAC的工作原理

MAC有深厚的数学背景,存在好的和坏的实现方案。因此,通常应该使用现有的、经过充分研究的标准方案,而不是冒险自创。幸运的是,标准协议通常会指定应该使用哪种MAC算法。

大多数MAC的理念是通信双方共享一个秘密密钥 S。这个密钥是一个随机生成的位串,因此很难被猜测或计算。消息认证码 C 是通过将MAC算法应用于消息 M 和密钥 S 而生成的:
C = MAC(M, S)

该算法具有一个关键属性:如果不知道密钥 S,那么为任何消息 M 生成正确的 C 异常困难。同样,给定一个MAC值 C,也很难找到一个能产生该 C 的消息 M。此外,即使你拥有一些 (M, C) 对,它们也几乎不会泄露关于密钥 S 的任何信息。

加密强度强的MAC有一个有趣的属性:如果你更改 M 中的一个位,这将导致一个全新的、看起来完全随机的MAC值 C'C' 中任何一位为0或1的概率都是50%,并且与原来的 C 无关。如果不是这样,那么攻击者就可以通过翻转一些位(例如修改交易金额)来轻松生成具有正确MAC的恶意消息。

从技术上讲,这意味着消息认证代码没有错误检测的保证。如果你翻转一个位,你可能会(尽管概率极低)得到与原始MAC相同的MAC。因此,MAC首先和主要是一种安全机制。虽然一个强大的机制同时能提供错误检测和安全是件好事,但其安全特性意味着它在纯粹的随机错误检测方面不如CRC等专用方法。

算法对比与总结

让我们通过一个对比表格来回顾三种算法的关键特性:

以下是三种算法对不同类型错误的检测保证对比(“是”表示保证能检测,“否”表示不保证):

错误类型 校验和 8位CRC 16位CRC MAC
单个位错误
两个位错误
长度≤8位的突发错误
长度=9位的突发错误
相隔很远的两个位错误

查看此矩阵,你可能会认为错误检测算法的保证非常有限。但请注意,“保证”是一个非常强的声明。虽然一个8位校验和无法保证捕获9位突发错误,但捕获的概率仍然很高。同样,一个16位CRC也有很高的概率检测到相隔很远的两个位错误。

在实际应用中,高概率往往就足够好了。如果失败很少发生,那么只需要偶尔执行一些更昂贵的恢复操作即可。这也意味着在实际网络中,我们往往采用多层错误检测:

  • 链路层使用CRC。
  • 网络层(IP)使用校验和。
  • 传输层(TCP)再次使用校验和。
  • 最终,应用程序通常还有自己的错误检测或校验机制。

所有这些层次叠加在一起,使得错误能够渗透而不被发现的几率变得非常非常低。

端到端原则的体现

数据错误检测是“端到端原则”的一个绝佳例子。实际上,这正是该原则的驱动力之一。每一层只能通过进行端到端的检查来确保它正确地通信数据:

  • 以太网需要确保其帧没有错误,以便正确解析,所以它有自己的CRC。
  • IP需要确保其数据包没有错误,以便正确解析。IP不能依赖以太网所做的检查,因为以太网卡或驱动程序可能在检查之后引入错误,所以IP必须在网络层进行自己的端到端检查(使用校验和)。
  • 使用消息认证码的TLS是另一个有趣的例子。它对错误检测的要求与IP或以太网大相径庭——它主要追求安全性。因此,它必须提供自己从开始到结束的错误检测(和安全)方案,因为这是确保其安全要求的唯一方式。

本节课中,我们一起学习了三种核心的错误检测算法:校验和、循环冗余校验(CRC)和消息认证码(MAC)。我们了解了它们的基本原理、计算方式、优缺点以及各自在网络协议栈不同层次中的应用。理解这些差异有助于我们设计更健壮、更安全的网络系统和协议。

课程 P28:有限状态机(FSM)基础 🧠

在本节课中,我们将要学习有限状态机(Finite State Machine, FSM)的基本概念。这是一种在描述网络协议和系统行为时非常常用的模型。我们将了解其构成要素、绘制规范,并最终通过分析TCP协议中用于建立和拆除连接的经典状态机来巩固理解。

什么是有限状态机?

正如其名称所示,有限状态机由有限数量的状态组成。状态代表了系统在某一时刻的特定配置。

为了便于理解,我们从一个抽象的例子开始。假设一个系统有三个状态:状态一状态二状态三。系统在任何时刻都只能处于这三个状态中的一个。

状态与转换

状态之间的(或箭头)定义了系统如何从一个状态转换到另一个状态。这种转换由事件触发。

当我们绘制一条转换边时,首先需要标明导致转换的事件。在事件下方,我们可以声明当该转换发生时系统将执行的动作。动作部分是可选的,因为并非所有转换都伴随动作。

状态 --[事件/动作]--> 新状态

如果系统处于某个状态时发生了一个事件,但该事件没有对应的转换边被定义,那么有限状态机在该情况下的行为是未定义的。

转换规则

从一个状态出发,可以有多条转换边,每条边对应不同的事件。例如,从状态一可以因事件A转换到状态二,也可以因事件B转换到状态三

然而,对于任何一个给定的状态,同一个事件不能对应多个不同的转换。否则转换将是模糊的,系统无法确定应该进入哪个新状态。

一个简化的HTTP请求示例

上一节我们介绍了状态机的基本构成,本节中我们来看一个简化的HTTP请求流程示例。

我们可以这样描述一个非常简单的网页加载系统:

  • 起始状态(空闲):用户正在浏览页面或处于空闲状态。
  • 事件:用户请求加载一个新页面。
  • 转换:系统从“空闲”状态转换到“请求页面”状态。
  • 动作:打开与Web服务器的连接。

一旦连接打开,系统就处于“请求页面”状态。当页面上的所有资源都加载完毕,连接关闭时(事件:连接关闭),系统将转换回“空闲”状态。

但这个模型过于简单。实际上,在请求页面时,我们可能需要逐个请求多个资源(如图片、脚本)。因此,我们需要一个额外的“请求待处理”状态。

以下是描述这个流程的状态列表:

  1. 空闲:初始状态。
  2. 请求页面:已打开连接,正在处理页面请求。
  3. 请求待处理:已发出对某个资源(如图片)的HTTP请求,正在等待服务器的响应。

这个三状态系统虽然简单,但并未明确定义所有可能发生的情况。例如,如果在“请求待处理”状态时连接突然关闭了怎么办?或者在“空闲”状态时意外收到了服务器响应?

为了完全明确,理论上应该为每个状态下的每个可能事件都定义转换。但这会导致状态机变得非常复杂,拥有大量的边。

因此在实际规范(如IETF的协议文档)中,通常只描述最常见、保证互操作性所必需的路径,并通过附加文本来说明其他情况,或允许部分行为未定义,为未来的实现和扩展留出灵活性。

实战分析:TCP连接状态机 🖥️

现在,让我们通过一个实际的、可能是互联网上最著名的有限状态机例子来巩固所学——TCP协议的状态机

下图描述了TCP连接的整个生命周期,包括建立、数据传输和关闭。它看起来复杂,共有约十一个状态,但我们可以分部分理解。

这个图表大致可分为四个部分:

  • 顶部(建立连接):描述TCP三次握手的过程。
  • 中部(已建立):连接成功建立后,进行数据传输的状态。
  • 下部(关闭连接):描述连接如何正常关闭。
  • 底部(关闭):连接完全终止,系统可以释放相关资源。

解读三次握手

记住,TCP使用三次握手来建立连接。让我们结合状态机来一步步看:

  1. 客户端(主动打开者)发起

    • 程序调用 connect()
    • 事件connect调用。
    • 转换:从 CLOSED 状态转换到 SYN-SENT 状态。
    • 动作:向服务器发送一个 SYN(同步)报文。
  2. 服务器(被动打开者)响应

    • 服务器程序已调用 listen(),处于 LISTEN 状态。
    • 事件:收到 SYN 报文。
    • 转换:从 LISTEN 状态转换到 SYN-RCVD 状态。
    • 动作:向客户端发送 SYN-ACK(同步-确认)报文。
  3. 客户端确认

    • 客户端处于 SYN-SENT 状态。
    • 事件:收到 SYN-ACK 报文。
    • 转换:从 SYN-SENT 状态转换到 ESTABLISHED 状态。
    • 动作:向服务器发送 ACK(确认)报文。
  4. 服务器完成连接

    • 服务器处于 SYN-RCVD 状态。
    • 事件:收到 ACK 报文。
    • 转换:从 SYN-RCVD 状态转换到 ESTABLISHED 状态。

至此,双方都进入了 ESTABLISHED 状态,可以开始双向数据传输。通过这个例子,你可以看到状态机如何清晰地刻画了协议双方在每一步收到特定报文(事件)后应如何反应(动作)并改变自身状态。

总结

本节课中我们一起学习了有限状态机的核心概念。我们了解到FSM由状态事件转换(及可选的动作)构成,是描述具有清晰状态变化的系统(如网络协议)的强大工具。我们探讨了其绘图规范,并通过分析简化的HTTP流程和复杂的TCP连接状态机,看到了FSM如何从抽象模型应用到实际场景中。理解FSM是深入理解许多计算机系统,尤其是网络协议工作原理的基础。

课程P3:四层互联网模型 🌐

在本节课中,我们将学习互联网的四层模型。这个模型描述了互联网如何通过分层协作,使各种应用程序能够可靠地通信。我们将从最底层开始,逐层向上,了解每一层的职责和工作原理。


概述

在上一节视频中,我们学习了如BitTorrent等多种不同的应用程序。Skype和网络都通过类似的模型在互联网上进行通信。本质上,这是一个双向可靠的字节流。创建我们应用程序的可靠通信模型需要大量的不同部分协同工作。尽管我们使用各种各样的互联网应用,发送各种类型的数据,速度也大相径庭,但应用程序发送和接收数据的方式有惊人的相似之处。

例如,应用程序想要发送和接收数据,无需担心数据在互联网上传输的路径或路线。几乎所有的应用程序都想要自信地知道他们的数据是否正确接收,对于丢失或损坏的数据,会自动重新传输,直到正确接收。

早期的互联网先驱创建了四层互联网模型,以描述构成互联网的操作层次,以便应用程序可以重复使用相同的构建块,无需为每个新应用程序从零开始创建它们。分层是一个很重要且经常使用的网络概念,我们在这门课程中会看到它很多次。


链路层 🔗

我们从链路层开始。互联网是由主机、链接和路由器组成的。数据通过每个链接逐跳传递。数据以包形式传递。一个包是一个自包含的单位,包含我们要传递的数据,以及一个告诉网络的头部。包应被送达的地方、它来自哪里等信息都包含在头部中。

链路层的工作是将数据逐个链接传输。你可能听说过以太网和Wi-Fi,这些都是不同链路层的两个例子。


网络层 🌍

对我们来说,上一层是最重要的一层:网络层。网络层的工作是将数据包从源到目的地在整个互联网上传输。从源到目的地,数据包是网络的重要构建块。

“包”是我们给那个数据集起的名字,带有一个描述数据内容的标题和一个标题,它要去哪里,它来自哪里。正如我们在上一张幻灯片中看到的,你经常会看到包被画成这样。网络层包被称为数据报,它们由一些数据和一个头部组成,其中包含发件人和收件人的地址,就像我们在信上写上发件人和收件人地址一样。

网络将数据包交给链路层,告诉它发送数据包通过第一个链路。换句话说,链路层为网络层提供服务。本质上,链路层在说:如果你给我一个数据包要发送,我会为你通过链路传输它。

链路的另一端是一个路由器。路由器的链路层接受数据包从链路,并将它交给路由器内部的网络层。路由器的网络层检查数据包的目的地址,并负责逐跳路由数据包,直到其最终目的地。它通过将其发送回链路层再次携带到下一个链路来完成此操作,然后传递给下一个路由器的网络层。

就这样,一直传递到目的地的网络层。最终,请注意,网络层不需要关心链路层如何将数据包发送过每个链路。实际上,不同的链路层工作方式非常不同,以太网和Wi-Fi显然非常不同。我们将在后续的学习中更详细地了解它们。

网络层和链路层之间的这种关注点分离允许每个层专注于其工作,无需担心其他层的工作方式。这也意味着单个网络层有一个与许多不同链路层通信的共同方式,只需将它们的数据包交给发送。这种关注点分离是由每个层的模块化实现的,以及到下层的共同、明确定义的API。

在互联网中,网络层是特殊的。当我们将包发送到互联网时,我们必须使用互联网协议,这是互联网协议或IP。它把互联网连接在一起。我们将在后续的视频中学习IP的更多细节,但现在了解一些IP的基本事实是很好的。

首先,IP尽最大努力将我们的数据包送达另一端,但它不作任何承诺。其次,IP数据包可能会丢失,它们可能会按顺序送达,并且可能会被损坏,没有保证。这可能会让你感到惊讶,你可能在问互联网如何工作,当数据包不能保证被送达时。

如果应用需要保证其数据在必要时会被重新传输,并且会被正确地送达给应用,没有任何损坏,那么它就需要在IP之上运行另一个协议。那就是传输层的工作。


传输层 📦

最常见的传输层是TCP,或者你可能听说过的TCP/IP。这是当应用同时使用TCP和IP时。TCP的任务是确保由应用发送的数据,在互联网的一端被正确地送达,并以正确的顺序传递给应用,在互联网的另一端。

如果网络层丢失了一些数据包,TCP会多次传输它们,如果需要。如果网络层将它们以错误的顺序送达,也许因为两个包以不同的路径到达目的地,TCP会将数据重新排列成正确的顺序。在后续的视频中,你将学习很多关于TCP和它如何工作的知识。

你需要记住的主要事情是,TCP为应用提供了一种服务,那保证在网络层服务之上的数据以正确的顺序送达。网络层正在提供一种不可靠的数据包送达服务。正如你可以想象的,如Web客户端或电子邮件客户端等应用发现TCP非常有用。通过使用TCP确保数据的正确送达,它们不必担心在应用中实现所有机制。他们可以利用其他开发者多年来的努力正确地实现TCP,然后重新使用它来正确地送达数据。重用是分层的一大优势。

但不是所有应用都需要数据以正确的顺序送达。例如,如果视频会议应用正在发送一个包中的视频片段,等待包多次重新传输可能没有意义,只是为了继续前进。一些应用不需要TCP服务。例如,如果应用不需要可靠的送达,它可以使用更简单的UDP或用户数据报协议。

UDP是另一种传输层,它打包应用数据,并将其交给网络层以送达另一端。UDP不提供任何送达保证。换句话说,应用至少有两种不同的传输层服务可以选择:TCP和UDP。确实存在,实际上,还有许多其他可能的选择,但是最常用的传输层服务就是TCP和UDP。


应用层 💻

最后,我们到达了四层模型顶部的应用层。当然,互联网上有数以千计的应用程序。虽然每个应用程序都不同,它可以通过使用定义良好的API重用传输层,从应用层到TCP或UDP服务下方的服务。

正如我们在上一视频中看到的,应用程序通常希望在两个端点之间建立一个双向可靠的字节流。他们可以发送任何字节流他们想要,并且应用程序有自己的协议,来定义在两个端点之间流动的数据的语法和语义。

例如,正如我们在上一视频中看到的,当Web客户端从Web服务器请求页面时,Web客户端发送GET请求。这是HTTP协议中的一个命令,或HTTP规定,GET命令应以ASCII字符串发送,连同要请求的页面URL。

直到应用层为止,GET请求直接发送到其对等端,在另一边,Web服务器应用程序。应用程序不需要知道数据是如何到达那里的,或Web客户端需要多少次重传数据。应用层将GET请求交给TCP层,它提供确保可靠交付的服务。它这样做使用网络层的服务,网络层又使用链接层的服务。

我们说每个层都与其对等层通信,就好像每个层只与同一层通信一样,在链接或互联网的另一边,不考虑下层如何将数据送到那里。


总结

总的来说,网络工程师发现将构成互联网的所有功能组织成层是很方便的。在最上面是应用,如BitTorrent或Skype,或万维网,它与目的地的对等层通信。

当应用程序有数据要发送时,将数据交给传输层。它的任务是将数据可靠或不可靠地送达另一端。传输层将数据发送到另一端,将其交给网络层。网络层的任务是将数据分解为包,每个包都有正确的目的地地址。最后,包被交给链接层,它有责任将包从一个跳点到下一个跳点传递。

在途中,数据从一个路由器跳到另一个路由器,一步一步地从一个路由器到目的地。网络层将数据逐个传送给下一个路由器,直到它到达目的地。数据被传递到层直到到达应用。

所以总的来说,应用双向、应用程序之间的可靠字节流通常但不是总是,并且它们使用特定于应用的语义,我们将在后来学习,例如HTTP或BitTorrent。

传输层通常保证数据的正确顺序、数据的端到端交付和控制拥塞,尽管一些应用不需要这个,因此它们可以使用不同的传输层。相反,网络层将数据包从源端到目的地传递,它提供了一种尽力而为的交付服务,没有保证,我们必须使用互联网协议。

链路层在单个链路上传输数据,在源主机和路由器之间,或者在两个路由器之间。


补充说明

我想让你知道两件额外的事情。第一件是,IP经常被称为互联网的薄雾。这是因为如果我们想要使用互联网,我们必须使用互联网协议,我们别无选择。但是,我们对链路层有很多选择,IP在许多上运行,许多不同链路层,例如以太网、Wi-Fi、DSL、3G、蜂窝等等。

在IP层之上,我们可以选择许多不同的传输层。我们已经听说过TCP和UDP,还有RTP用于实时数据,还有许多其他。当然,在上面坐着成千上万种不同的应用程序。

我想让你知道的第二件事是,在1980年代,国际标准化组织或ISO创建了一个七层模型来代表任何类型的网络。它被称为七层开放系统互联连接或OSI模型。我们在这门课程中不需要花费任何时间来研究它,因为它已经被所有目的都等同于四层互联网模型所取代。

但如果你对此感兴趣,你会发现任何网络教材、维基百科对七层描述了大量的细节。七层模型定义了后来在四层互联网模型中被合并的层。例如,我们称之为链接的今天的链接层被分离为定义帧格式的链接层,和定义如电缆上的电压水*等物理层的层,或者连接器的物理尺寸。

在两种模型中,网络层基本上相同。传输和应用层在OSI模型中各由两层表示。这些都是常用的互联网协议示例,例如HTTP,它大部分数据在协议中都以ASCII格式传输,以及它们如何映射到今天的OSI编号方案。

你需要知道的七层OSI模型的唯一真实遗产是编号系统。你经常会听到网络工程师提到网络层作为层三,尽管它在互联网模型中是从底部的第二层。同样,人们会提到以太网作为链路,嗯,层二。


本节课中,我们一起学习了互联网的四层模型:链路层、网络层、传输层和应用层。每一层都有其独特的职责,并通过明确定义的接口与上下层协作,共同实现了互联网上复杂而可靠的通信。理解这个模型是学习计算机网络的基础。

课程P30:有限状态机(三)🚀

在本节课中,我们将继续学习有限状态机,通过一个具体的TCP连接状态转换案例,来理解当程序调用listen、接收到SYN以及调用close时,状态是如何变化的。


状态转换案例分析 🔍

上一节我们介绍了有限状态机的基本概念。本节中,我们通过一个具体问题来观察状态机的运行过程。

第一个问题的答案是“在LISTEN状态”。我们来分析原因。

系统从CLOSED状态开始。当用户程序调用listen()函数时,系统状态转换为LISTEN状态。

随后,当socket接收到一个SYN(同步)数据包时,状态从LISTEN转换为SYN_RECEIVED状态。

SYN_RECEIVED状态时,如果用户程序调用了close()函数,系统将沿着标有“close”事件的状态转移边进行转换。


核心步骤总结 📝

以下是上述过程的关键步骤总结:

  1. 初始状态CLOSED
  2. 触发事件:程序调用 listen()
  3. 状态转换CLOSEDLISTEN
  4. 触发事件:Socket 接收到 SYN 包。
  5. 状态转换LISTENSYN_RECEIVED
  6. 触发事件:程序调用 close()
  7. 状态转换:从 SYN_RECEIVED 状态,根据“close”事件转移边进入下一个状态(通常是CLOSEDTIME_WAIT,取决于具体实现)。

本节课中,我们一起学习了TCP连接建立过程中一个典型的状态转换路径。我们看到了从CLOSED开始,经过LISTENSYN_RECEIVED状态,最终可能因close调用而结束的过程。理解这些状态和转换是掌握网络编程中socket行为的基础。

计算机网络课程 P31:TCP连接关闭的有限状态机详解 🔄

在本节课中,我们将深入学习TCP协议如何关闭一个连接。我们将通过分析一个有限状态机来精确理解TCP连接关闭过程中的各种状态和转换,这比单纯的口语描述要精确得多。


上一节我们介绍了TCP连接建立的过程,本节中我们来看看TCP连接是如何优雅关闭的。

连接关闭的起点

第二个问题的答案是“关闭的”。TCP连接从关闭状态开始。

当用户程序调用 connect() 系统调用时,连接会从关闭状态过渡到 SYN_SENT 状态。

SYN_SENT 状态中,如果用户程序调用 close(),那么状态会沿着一条边直接回到关闭状态。

已建立的连接

当连接成功建立后,我们的socket就处于建立状态,双方可以开始交换数据。

TCP关闭连接的六个状态

蓝色框中的六个状态描述了TCP如何关闭一个连接。

谈论“关闭”连接有时需要区分,因为“关闭”在系统调用中有一个特定含义。一个连接在一方关闭它之后,可能仍然存在。

TCP建立连接和关闭连接的过程存在对称性。连接建立使用 SYN(同步)包,而连接关闭则使用 FIN(结束)包。

主动关闭与被动关闭

如果连接的任意一方首先调用 close(),它将进入 FIN_WAIT_1 状态。这使它向连接的另一端发送一个 FIN 包。

发起这个操作的一方被称为主动关闭者

另一方接收到 FIN 包后,会沿着状态图的蓝色边移动到 CLOSE_WAIT 状态。它会保持在这个状态,直到其内部的用户程序也调用 close()。这时,它才会发送自己的 FIN 包。

连接关闭的复杂性

这里情况变得复杂,因为TCP连接是双向的

主动关闭者已经关闭了自己方向的连接,所以它不能再发送任何数据。但被动关闭者可能还有数据要发送。因此,被动关闭者可以继续发送数据,而主动关闭者接收并确认这些数据。或者,被动关闭者也可以选择关闭自己这一侧。

甚至可能出现双方几乎同时决定关闭连接的情况,这样网络上就会有两个 FIN 包交叉传递。

三种可能的关闭结果

以下是连接关闭时可能出现的三种情况:

  1. 半关闭(Half-Close):被动关闭者确认(ACK)了主动关闭者的 FIN,但没有立即发送自己的 FIN。在这种情况下,被动关闭者处于 CLOSE_WAIT 状态,并可以继续发送数据。主动关闭者则进入 FIN_WAIT_2 状态。
  2. 顺序关闭(Orderly Close):被动关闭者在确认(ACK)主动关闭者的 FIN 后,也发送了自己的 FIN。这是通往 TIME_WAIT 状态的中间路径。
  3. 同时关闭(Simultaneous Close):双方几乎同时主动关闭,都向对方发送了 FIN。在这种情况下,双方都处于 FIN_WAIT_1 状态。每一方都会收到一个并非回应自己 FINFIN 包,这时双方会转换到 CLOSING 状态。

最终状态:TIME_WAIT 与 CLOSED

当主动关闭者发送的 FIN 被对方确认(ACK)后,它会从 FIN_WAIT_2 状态切换到 TIME_WAIT 状态。

TCP保持在 TIME_WAIT 状态一段时间(通常是2MSL,即两倍的最大段生命周期),以确保网络中所有属于此连接的旧数据包都已消失,之后才可以安全地切换到 CLOSED 状态。

LAST_ACK 状态到 CLOSED 状态的最后一条蓝色边,发生在被动关闭者发送的 FIN 被确认时。

总结与意义

一方面,这是一个包含大量细节的模型,有十二个状态,覆盖了许多边界情况。

但我希望你能看到,这个有限状态机如何将之前口语化的描述变得具体和精确。试图仅基于口语描述来实现一个正确、健壮的TCP协议将非常困难。而这个状态图精确地规定了TCP在各种情况下的行为,是协议实现的可靠蓝图。

本节课中,我们一起学习了TCP连接关闭的完整过程,通过分析有限状态机,我们理解了主动关闭被动关闭半关闭以及同时关闭等不同场景下的状态流转。掌握这个状态机对于深入理解TCP协议的可靠性和复杂性至关重要。

课程 P32:停止等待协议 🛑⏳

在本节课中,我们将要学习流量控制的基本概念,并深入探讨其最简单的实现方式——停止等待协议。我们将了解它如何解决发送与接收速度不匹配的问题,以及其基本工作原理和潜在缺陷。


概述

流量控制是可靠高效通信的基本构建块之一。它试图解决的核心问题是:当发送者发送数据的速度快于接收者处理数据的速度时,会导致数据包丢失和网络资源浪费。本节课将首先介绍流量控制的基本原理,然后重点讲解其最简单的实现——停止等待协议。


流量控制要解决的问题

上一节我们概述了课程目标,本节中我们来看看流量控制具体要解决什么问题。

当发送者可以发送数据的速度比接收者可以处理的速度更快时,就会出现问题。例如,发送者A每秒可以发送500万个数据包,但接收者B每秒只能处理200万个数据包。这可能是因为B的处理器速度较慢、网卡性能不足或其他原因。

因此,如果A以每秒500万个数据包的满速率发送,那么其中300万个数据包将不得不被B丢弃,因为B无法处理它们。实际上,只有五分之二的数据包能够成功通过。这对发送者A来说是巨大的浪费,也造成了网络资源的极大消耗,并且会完全占满接收者B。

发送者A没有理由以快于接收者B处理速度的速率发送数据。因此,流量控制的基本方法是:确保发送者不会发送比接收者能处理的更多的数据包。接收者需要以某种方式向发送者提供反馈(无论是隐式还是显式),指示发送者应该减速、加速或设置队列。


两种基本方法

目前大多数协议主要使用两种基本方法来实现流量控制。

  • 停止等待协议:这是本视频首先讨论的方法,非常简单,易于实现为一个非常简单的有限状态机。
  • 滑动窗口协议:这个方法将在后续视频中提到,它稍微复杂一些,但能提供更好的性能。

在深入协议细节之前,我们先简要复习一下有限状态机图。当我们绘制一个协议的有限状态机时,我们展示它可以进入的状态(例如状态一、状态二、状态三)。状态之间的边包含两个信息片段:上方是引起状态转换的事件下方是状态转换时执行的动作


停止等待算法原理

上一节我们介绍了流量控制的两种基本方法,本节中我们来看看停止等待算法的核心思想。

停止等待算法非常简单:它规定在任何时间,从发送者到接收者最多只能有一个数据包在传输中(即“在途”)

基本算法如下:

  1. 发送者发送一个数据包。
  2. 然后等待接收者的确认(ACK)。
  3. 当收到确认后,如果还有更多数据要发送,就发送下一个数据包。
  4. 如果等待一段时间(即超时)后仍未收到确认,发送者就假设数据包已丢失(可能在网络中被路由器丢弃,或确认包被丢弃),然后它重新发送该数据包。

协议状态机

理解了基本算法后,我们来看看协议双方的具体行为如何用状态机描述。

接收者有一个单一状态的有限状态机:

  • 事件:当它收到新数据时。
  • 动作:它为那个数据发送一个确认(ACK)。如果数据是新的,它还将这个数据传递给上层应用程序。

发送者的有限状态机有两个状态:

  1. 等待数据状态:在此状态中,协议准备发送数据,但应用程序尚未提供要发送的数据。
    • 事件:当应用程序调用发送函数时。
    • 动作:协议发送包含该数据的包(或能装入包的最大数据量),然后进入“等待ACK状态”。
  2. 等待ACK状态:在此状态中,有两个可能的转换:
    • 事件1:收到确认(ACK)。
      • 动作:回到“等待数据状态”。如果有更多数据要发送,就发送新数据;如果没有,就等待应用程序再次调用发送。
    • 事件2:超时。
      • 动作:重新发送之前的数据包,然后继续等待ACK。

发送者需要谨慎选择超时时间,以确保在超时发生时,数据包或随后的确认几乎肯定已经丢失。该协议的核心是在任何时间只有一个数据包在网络中传输


执行示例分析

以下是停止等待协议的四个典型执行示例,帮助我们理解其在不同场景下的行为。

情况一:无丢失(理想情况)
一切完美工作。发送者发送数据(DATA),接收者接收后发送确认(ACK)。发送者收到ACK后,如果有更多数据,就可以发送下一个。

情况二:数据丢失
发送者发送数据,但数据包在网络中丢失。发送者等待ACK超时,然后重新发送数据包。

情况三:数据成功,但确认丢失
数据成功交付给接收者,接收者也发送了ACK,但ACK在网络中丢失。发送者超时,并重新发送数据。这导致接收者(收到重复数据)发送一个新的ACK。此时,发送者收到ACK并继续正常操作。

情况四:延迟确认导致的复杂性
这个情况稍微复杂,揭示了基本算法的一个潜在问题。假设发送者发送数据,接收者发送ACK,但网络中发生拥堵(例如链路变慢或队列过长),导致ACK被严重延迟,超过了发送者的超时时间。

  1. 发送者超时,重新发送数据。
  2. 不久之后,那个被延迟的ACK(针对原始数据包)终于到达发送者。
  3. 发送者知道数据已被确认,于是发送下一个新数据包。
  4. 如果这个新数据包丢失了,而之前重传的第一个数据包到达了接收者,接收者会为这个(它认为是重复的)数据包再次发送ACK。

此时,发送者面临一个问题:它收到的这个ACK,到底是针对旧数据包的重传,还是针对新数据包的?如果它错误地假设这个ACK是针对新数据的,那么它可能认为新数据已成功送达(实际上已丢失),从而导致错误。在任何可靠的流量控制协议中,一个基本问题就是:如何检测重复的数据包和确认?如何区分确认是针对重传包还是新数据包?


解决方案:序列号

针对上述重复检测的问题,停止等待协议可以使用一个一位序列号(1-bit sequence number) 来解决。

思路是在所有数据包和确认包中都使用这个一位计数器。例如:

  • 发送者先发送 数据0(DATA 0)
  • 接收者回复 确认0(ACK 0)
  • 发送者然后发送 数据1(DATA 1)
  • 接收者回复 确认1(ACK 1),依此类推。

这样,接收者就能通过序列号判断收到的是新数据还是重复数据。在前面提到的复杂情况中,接收者可以通过序列号区分ACK是针对“数据0”的重传,还是针对“数据1”的首次传输。

然而,这种一位计数器方法基于两个简化假设:

  1. 网络本身不会复制数据包
  2. 数据包不会因延迟超过多个超时周期而失效(例如,一个“数据0”包被延迟了很长时间,在发送者已经发送“数据1”后才到达,导致接收者错误地将其当作新数据)。

在实际中,可以通过增加序列号的空间(例如使用更多比特的序列号)来解决这些问题,但对于理解简单的协议运行原理,这些简化假设是合适的。


总结

本节课中,我们一起学习了流量控制的重要性及其最简单的实现——停止等待协议。我们了解了它通过“发送-等待-确认”的机制,确保同一时间只有一个数据包在传输,从而解决收发速度不匹配的问题。我们还分析了其基本状态机、几种典型的执行情况,以及使用一位序列号来解决数据包和确认包的重复问题。虽然停止等待协议简单且易于实现,但其效率较低,这引出了我们后续将要学习的、性能更优的滑动窗口协议。

计算机网络课程 P33:滑动窗口协议 🪟

在本节课中,我们将要学习一种比“停止-等待”协议更高效的流量控制算法——滑动窗口协议。我们将了解其工作原理、核心概念以及如何通过它来充分利用网络带宽。


概述

上一节我们介绍了简单的“停止-等待”协议。本节中,我们来看看它的一个通用化版本——滑动窗口协议。该协议允许在任意时刻有多个数据包在网络中传输,从而显著提高了网络链路的利用率。


“停止-等待”协议的局限性

“停止-等待”协议在任何时刻最多只允许一个数据包在传输中。其基本流程如下:

  1. 发送方发送一个数据包。
  2. 接收方收到后,发回一个确认(ACK)。
  3. 发送方收到ACK后,才能发送下一个数据包。
  4. 如果发送方超时未收到ACK,则重发该数据包。

虽然这个协议简单可靠,但它有一个主要问题:效率低下

假设在波士顿和旧金山之间有一条10 Mbps的链路,往返时间(RTT)为50毫秒。我们发送的数据包大小为12千比特(约1.5KB)。那么:

  • 每秒可以进行的往返次数:1000 ms / 50 ms = 20 次。
  • 每秒最多可发送的数据包数:20个。
  • 因此,最大有效吞吐量为:20 包/秒 * 12 千比特/包 = 240 千比特/秒

然而,链路的实际带宽是10 Mbps(即10,000千比特/秒)。这意味着“停止-等待”协议只利用了 240 / 10000 = 2.4% 的链路容量,效率极低。


滑动窗口协议的基本思想

为了解决上述问题,滑动窗口协议允许最多有 n 个数据包同时在网络中传输(即“在飞行中”)。

  • n = 1 时,滑动窗口协议就退化为“停止-等待”协议。
  • 通过将 n 设置为一个合适的值,可以让发送方持续不断地发送数据,从而“填满”整个传输管道,使吞吐量达到链路瓶颈带宽。

沿用上面的例子,要填满50ms的RTT管道,并达到10 Mbps的速率,我们需要计算所需的窗口大小(以数据包计):

  • 每个RTT内需要传输的数据量:10 Mbps * 50 ms = 500 千比特
  • 每个数据包12千比特,因此需要的窗口大小约为:500 / 12 ≈ 42 个数据包。

通过设置窗口大小为42,理论上我们就可以让发送方以10 Mbps的速率持续向接收方发送数据。


滑动窗口算法详解

让我们更具体地看看发送方和接收方是如何维护滑动窗口的。为了简化,我们以数据包编号为单位进行讨论(实际协议如TCP以字节为单位)。

发送方规则

发送方维护三个关键变量:

  • 发送窗口大小 (SWS): 允许的未确认数据包最大数量。
  • 最后收到的确认号 (LAR): 发送方已收到的、连续被确认的最大数据包序号。
  • 最后发送的段号 (LSS): 发送方已发送的最大数据包序号。

发送方必须始终遵守以下不变式:

LSS - LAR <= SWS

这意味着,如果最后确认的包是 n,那么发送方不能发送序号超过 n + SWS 的数据包。

发送方的工作流程如下:

  1. 初始化 LAR = -1, LSS = -1
  2. 只要 LSS - LAR < SWS,就可以发送下一个数据包(序号为 LSS + 1),并更新 LSS
  3. 当收到一个确认号为 n 的ACK时,更新 LAR = n(假设是累积确认,见下文)。这相当于窗口向前“滑动”,发送方可以发送新的数据包。
  4. 如果发生超时,则重传 LAR + 1 号数据包(即窗口中最旧的那个未确认包)。

一个重要特性是: 窗口的移动受限于第一个未确认的数据包。即使窗口后面的包已经到达并被确认,窗口也不能跳过这个缺口向前滑动。这确保了数据的顺序交付。

接收方规则

接收方也维护三个变量:

  • 接收窗口大小 (RWS): 愿意缓冲的数据包数量。
  • 最后可接受的段号 (LAS): 愿意接收的最大数据包序号,LAS = LFR + RWS
  • 最后接收的段号 (LFR): 连续收到的最大数据包序号。

接收方遵守的不变式是:

LAS - LFR <= RWS

接收方的工作流程如下:

  1. 收到序号为 seq 的数据包。
  2. 如果 seq <= LFR,说明是重复包,丢弃它,但仍然需要发送一个ACK(ACK号为 LFR),以防之前的ACK丢失。
  3. 如果 LFR < seq <= LAS,则接收该包并缓存。如果 seq == LFR + 1(即正是期望的下一个包),则更新 LFR,并可能连续交付一批已按序到达的包。
  4. 如果 seq > LAS,说明超出接收窗口,直接丢弃。
  5. 无论是否接收数据包,接收方通常会回送一个ACK,其中包含当前的 LFR 值(即下一个期望的序号)。这就是累积确认

累积确认与序列号空间

累积确认

在基本的滑动窗口协议中,确认是累积性的。确认号 n 表示接收方已经正确收到了序号 n 及之前的所有数据。

  • 优点:简单,ACK丢失时冗余的后续ACK可以提供相同信息。
  • 缺点:无法精确告知哪些包丢失。现代协议(如TCP)有选择性确认(SACK) 作为扩展来解决这个问题。

注意:TCP的确认号略有不同,它表示“期望收到的下一个字节的序号”。例如,若正确收到0-99字节,则发回的ACK号是100。

序列号空间大小

我们需要多大的序列号范围来避免歧义?这与窗口大小有关。

  • 在“停止-等待”(SWS=1, RWS=1)中,需要2个序列号(0和1)。
  • 推广到滑动窗口,所需的序列号空间至少为:
    序列号空间大小 >= SWS + RWS
    
    这是为了区分是重传的老数据包,还是延迟到达的新数据包。

一个特例是回退N步(Go-Back-N)协议,其中 RWS = 1SWS > 1。此时,任何一个包丢失,发送方都需要回退并重传其后已发送的整个窗口的数据,效率较低。此时需要的序列号空间为 SWS + 1


TCP中的滑动窗口

TCP是一个使用滑动窗口进行流量控制可靠传输的协议。

  • 流量控制:接收方通过TCP头部的 窗口大小(Window Size) 字段,告知发送方自己还有多少空闲缓冲区(以字节为单位)。这动态决定了发送方的有效 SWS
  • 发送规则:发送方不能发送序号超过 确认号 + 接收方通告窗口 的数据。
  • 大序列号空间:TCP使用32位的序列号空间,足以应对高速网络下长延迟的旧数据包带来的歧义问题。

总结

本节课中我们一起学习了滑动窗口协议:

  1. 核心思想:通过允许 n 个未确认数据包同时在途,来提升链路利用率,填满传输管道。
  2. 关键算法:发送方和接收方分别维护窗口,通过序列号和累积确认来协调数据的发送、接收与重传。
  3. 重要关系:协议正确运行所需的最小序列号空间为 SWS + RWS
  4. 实际应用:TCP协议使用滑动窗口机制实现可靠的、流量受控的字节流传输,其中接收方通过通告窗口来动态控制发送速率。

滑动窗口协议是理解现代网络通信(尤其是TCP)如何高效、可靠传输数据的基石。

课程 P34:可靠通信中的重传策略 🚀

在本节课中,我们将探讨可靠传输协议中的重传策略,特别是滑动窗口协议下的两种主要方法:回退N帧(Go-Back-N)与选择重传(Selective Repeat)。我们将通过简单的例子和对比,帮助你理解它们的工作原理、行为差异以及各自的适用场景。

概述 📖

为了实现可靠的数据传输,当数据包可能丢失时,协议必须有能力重新发送它们。在滑动窗口协议的框架下,这引出了两种核心的重传策略。我们将分析这两种策略的行为逻辑,并理解窗口大小等参数如何影响协议的表现。

重传的基本问题 ⚙️

滑动窗口可靠传输面临一个基本问题:我们有一个“在途”的数据包窗口(例如四个包),并且使用累积确认机制。这意味着我们只能获得关于“最后一个被成功接收的包”的反馈。

我们对每个已发送但未确认的包维护一个重传计时器。计时器基于包的发送时间设置,提供了一个保守的估计:如果在此时间之后仍未收到该包的确认,则几乎可以断定包已丢失,应当重传。

那么,给定这些参数,协议将如何表现?其重传策略会是怎样的?实际上,最终你会看到两种主要的策略。

两种重传策略 🔄

以下是两种主要的可靠传输重传策略。

策略一:回退N帧(Go-Back-N)

回退N帧是一种较为悲观或保守的方法。其核心行为是:如果窗口中的任何一个数据包丢失,发送方将重新传输整个未被确认的窗口内的所有数据包。

核心逻辑:假设窗口大小为 n。如果检测到第 k 个包丢失,发送方将“回退”并重传从第 k 个包开始的所有 n 个包(即当前窗口内的所有包)。

策略二:选择重传(Selective Repeat)

选择重传是一种更为乐观的方法。它假设:如果一个包丢失,只有那个特定的包丢失了,窗口内的其他包可能已成功送达。

核心逻辑:如果检测到某个包丢失(未收到确认),发送方将仅重传那个特定的包,而不是整个窗口。

策略行为对比 🧪

上一节我们介绍了两种策略的核心思想,本节中我们来看看它们在实际传输中具体如何表现。

回退N帧行为示例

假设发送窗口大小 n = 4

  1. 发送方发送包 1, 2, 3, 4。
  2. 包 2 在传输中丢失。
  3. 接收方成功接收包 1,并回复确认 ACK 1。它无法确认包 2,因此后续的 ACK 也会停滞。
  4. 发送方收到 ACK 1 后,可以滑动窗口并发送包 5。
  5. 此时,包 2 的重传计时器超时。在回退N帧策略下,发送方悲观地认为整个未确认窗口(包 2, 3, 4, 5)都可能有问题,因此会重传整个窗口(包 2, 3, 4, 5)。

这种方法非常保守,可能会重传许多实际上已成功接收的包(如本例中的包 3, 4, 5),造成带宽浪费。

选择重传行为示例

同样假设窗口大小 n = 4

  1. 发送方发送包 1, 2, 3, 4。
  2. 包 2 丢失。
  3. 接收方确认包 1(ACK 1),发送方因此可以发送包 5。
  4. 包 2 的重传计时器超时。在选择重传策略下,发送方仅重传丢失的包 2
  5. 接收方收到包 2 后,可以继续处理并确认已缓存的后续包(例如发送 ACK 5)。传输得以继续,仅重传了必要的包。

这种方法更高效,但假设丢失是孤立的。

为何不总是使用选择重传? 🤔

既然选择重传发送的数据包更少,为什么我们有时还需要回退N帧策略呢?主要有以下几个原因:

  1. 恢复速度:当出现连续多个包丢失(即突发丢失)时,选择重传需要为每个丢失的包单独等待其计时器超时,恢复速度可能较慢。而回退N帧一旦检测到丢失,便立即重传整个窗口,能更快地填补空缺。
  2. 接收方缓冲能力:策略的选择与接收方的窗口大小紧密相关。如果接收方只能按序接收(接收窗口为1),它无法缓存乱序到达的包。此时,任何包的丢失都会导致发送方行为退化为回退N帧模式。
  3. 实现复杂度:选择重传需要接收方能够缓存乱序包,并在发送方进行更精细的单个包重传管理,实现起来比回退N帧更复杂。

因此,这里存在一种权衡:在带宽利用率(浪费多少重传包)和从错误中恢复的速度之间进行取舍。

协议配置如何影响策略选择 ⚖️

上一节我们提到了接收方窗口的影响,本节我们通过两个具体配置例子,直观地看协议行为如何被塑造。

示例一:接收窗口为1 -> 行为类似回退N帧

  • 发送方窗口大小: n = 4
  • 接收方窗口大小: 1

过程分析

  1. 发送方发送包 1, 2, 3, 4。
  2. 包 2 丢失。
  3. 接收方收到包 1,确认 ACK 1,并将包 1 交付给上层。其窗口滑动,期待包 2。
  4. 发送方收到 ACK 1,发送包 5。
  5. 包 2 计时器超时,发送方重传包 2。
  6. 关键点:由于接收方窗口大小为1,它无法缓存乱序到达的包 3, 4, 5。因此,即使它收到了重传的包 2,它仍然没有收到包 3(它现在期待的下一个包)。它只能确认包 2。
  7. 发送方需要等待包 3 的计时器超时,然后重传包 3... 以此类推。这种行为实质上就是回退N帧,发送方被迫重传丢失包之后窗口内的每一个包。

示例二:接收窗口等于发送窗口 -> 行为类似选择重传

  • 发送方窗口大小: n = 4
  • 接收方窗口大小: n = 4

过程分析

  1. 发送方发送包 1, 2, 3, 4。
  2. 包 2 丢失。
  3. 接收方收到包 1,回复 ACK 1。它可以将乱序但正确的包 3, 4 缓存起来。
  4. 发送方收到 ACK 1,发送包 5。
  5. 包 2 计时器超时,发送方仅重传包 2
  6. 接收方收到包 2 后,由于它已缓存了包 3, 4,并且收到了包 5,它可以按序交付包 2, 3, 4,并发送一个累积确认,例如 ACK 5。
  7. 发送方收到 ACK 5,知道包 2, 3, 4, 5 均已安全接收,窗口大幅滑动。整个过程只重传了丢失的包 2,这是选择重传的典型行为。

实现注意事项 💡

当你自己实现传输协议(例如在实验作业中)时,设计重传策略需要考虑以下几点:

  • 避免过早重传:不要因为一个包(例如包2)的计时器超时,就冲动地重传整个窗口。很可能窗口中的其他包(3,4,5)已经正确到达接收方并正在被缓存。过早地重传它们会将网络中数据包的数量增加到超出你窗口允许的范围,加剧网络拥塞。
  • 策略选择:你可以选择保守的回退N帧策略,假设“一个包丢失,整个窗口都危险”。这在接收方缓冲能力有限时是自然的结果。你也可以选择更高效但稍慢的选择重传策略,只重传确认为丢失的单个包,这需要接收方有足够的缓存空间。
  • 管理网络负载:必须谨慎控制网络中未确认数据包的数量,重传策略是其中的关键一环。

总结 🎯

本节课中,我们一起学习了可靠传输协议中的两种核心重传策略:

  1. 回退N帧:悲观策略,丢失一个包则重传整个发送窗口。实现简单,恢复速度快,但可能浪费带宽。通常在接收方缓冲能力有限时自然出现。
  2. 选择重传:乐观策略,仅重传确认丢失的单个数据包。带宽利用率高,但实现复杂,且在连续丢包时恢复可能较慢。需要接收方有足够大的窗口来缓存乱序包。

协议的具体行为并非孤立由策略决定,而是由发送窗口大小接收窗口大小以及网络丢包模式共同塑造的。理解这些机制,有助于你设计出更适应特定网络环境的可靠通信协议。

课程 P35:TCP 头部详解 📖

在本节课中,我们将学习传输控制协议(TCP)头部的结构和各个字段的含义。TCP头部是确保数据在网络中可靠传输的关键组成部分。我们将逐一解析每个字段的作用,帮助你理解TCP是如何工作的。


概述 📋

TCP头部是附加在TCP数据段前面的信息,用于管理连接、确保数据顺序和完整性。标准的TCP头部长度为20字节,包含源端口、目的端口、序列号、确认号以及多个控制标志等重要信息。


TCP头部结构

标准的TCP头部长度为20字节。其结构通常可视化为五行,每行包含四个八位字节。此外,TCP头部之后还可以包含选项字段,但本教程主要关注基本的20字节头部结构。


端口字段

TCP头部的首两个字段是源端口目的端口,每个字段均为16位(2字节)。端口用于标识发送和接收数据的应用程序。例如,访问网页通常使用目的端口80


序列号与确认号

接下来是两个关键字段:序列号确认号

  • 序列号:表示本数据段中第一个数据字节的编号。
  • 确认号:表示接收方期望收到的下一个字节的编号。它等于已成功接收的最后一个字节的序号加1。

例如,如果发送一个序列号为4000且包含500字节数据的段,则该段包含字节4000至4499。接收方成功接收后,会回复一个确认号为4500的段,表示期望收到序号为4500的字节。


数据偏移与保留字段

数据偏移字段(4位)指示TCP头部长度(以32位字为单位),从而指明数据部分从何处开始。这是必要的,因为TCP头部可能包含长度可变的选项字段。其后是保留字段,目前未使用,应设置为0。


控制标志

以下是TCP头部的六个控制位(各占1位),它们管理连接状态和数据流:

  1. URG (紧急):当设置为1时,表示本段包含紧急数据,应优先处理。
  2. ACK (确认):当设置为1时,表示确认号字段有效。除了建立连接的初始SYN包,TCP通信中几乎所有的包都应设置此位。
  3. PSH (推送):提示接收方应立即将数据交付给上层应用程序,而不是等待缓冲区填满。
  4. RST (复位):当设置为1时,表示需要立即重置TCP连接,通常用于处理异常情况。
  5. SYN (同步):在连接建立时使用。发送方设置此位以发起连接,并指明其初始序列号。
  6. FIN (结束):当设置为1时,表示发送方已完成数据发送,希望关闭连接。

窗口大小

窗口字段(16位)用于流量控制。它告知对方,本端的接收缓冲区还有多少可用空间,即对方最多还能发送多少未被确认的数据。例如,窗口值为200000表示该方向上最多允许存在200,000个未确认的字节。


校验和与紧急指针

  • 校验和:用于检测TCP头部、数据部分以及一个由IP头部信息构成的伪头部在传输过程中是否出错。计算范围覆盖伪头部、TCP头部和TCP数据。
  • 紧急指针:仅当URG标志位设置为1时才有效。它与序列号字段相加,指向本报文段中紧急数据的最后一个字节的位置。

选项与填充

TCP头部可以包含选项字段,用于提供额外功能(如最大段大小协商)。选项的长度必须是4字节的整数倍,不足部分会用填充字节补足,以确保整个头部长度是32位的整数倍。


总结 🎯

本节课我们一起学习了TCP头部的详细结构。我们了解到,TCP通过20字节的标准头部(不含选项)管理端到端的可靠通信。关键组件包括:

  • 用于寻址的源端口和目的端口
  • 保证数据顺序的序列号确认号
  • 管理连接状态的各种控制标志(如SYN、ACK、FIN)。
  • 用于流量控制的窗口字段。
  • 确保数据完整性的校验和

理解TCP头部各字段的功能,是掌握TCP/IP协议栈中可靠数据传输机制的基础。

计算机网络课程 P36:TCP 连接建立与拆除详解 🔗

在本节课中,我们将深入探讨 TCP 协议中连接建立与拆除的完整过程。我们将学习标准的三次握手、四次挥手,以及“同时打开”等特殊情况。课程将结合状态机图、数据包抓包实例和核心概念公式,帮助你透彻理解 TCP 如何可靠地管理通信会话。


连接状态的重要性 🤔

上一节我们介绍了可靠通信的基本概念,本节中我们来看看为何在通信中维护状态如此重要。

如果我们想要实现可靠通信,让通信的一端或两端维护一些状态信息会非常有帮助。虽然理论上可以在两端都无状态的情况下实现可靠通信,但效率会低得多。

维护一点状态信息是非常有益的,它能显著提升吞吐量等性能指标。但既然我们引入了状态,就随之产生了两个问题:

  1. 我们如何建立这个状态(即连接建立)?
  2. 考虑到状态会占用内存,我们何时可以拆除并清理它?

这些连接建立与拆除的问题,也关系到 TCP 连接所使用的内存结构(如缓冲区)和端口号等资源的分配与回收。


TCP 报文段头部回顾 📦

在深入连接过程之前,我们先快速回顾一下 TCP 报文段的头部结构。

标准的 TCP 头部包括一个 20 字节的固定部分,以及可选的选项字段。在连接建立与拆除过程中,头部中的以下几个字段会被关键性地使用:

  • 序列号 (Sequence Number)
  • 确认号 (Acknowledgment Number)
  • SYN 标志位 (Synchronize)
  • ACK 标志位 (Acknowledge)
  • FIN 标志位 (Finish)

连接建立:三次握手 🤝

接下来,我们将通过握手过程来详细解释在交换的报文段中发生了什么。

回想标准的三次握手模型,我们有一个主动发起方和一个被动接收方。被动接收方(如 Web 服务器)监听并等待连接请求;主动发起方则发起连接。

以下是握手步骤的分解:

  1. SYN
    主动发起方发送一个设置 SYN=1 的 TCP 报文段。这表示它希望将被动方的序列号同步到流的起始位置。报文段中包含一个初始序列号,我们称之为 seq = S_A
    • 使用随机化的初始序列号 S_A 而非从 0 开始,主要出于安全考虑(防止他人猜测并插入数据),以及避免网络中延迟的旧报文段造成混淆。

  1. SYN-ACK
    被动接收方回应一个设置 SYN=1, ACK=1 的报文段。它说:“好的,我收到了你的 SYN。我的起始序列号是 seq = S_P。” 同时,它通过 ack = S_A + 1 来确认已收到主动方的 SYN。
    • 确认号 ack 总是期望收到的下一个字节的序列号。

  1. ACK
    主动发起方响应。它不需要再发送 SYN,因为同步已完成。因此它发送一个设置 ACK=1 的报文段,其序列号为 seq = S_A + 1,确认号为 ack = S_P + 1。这表示:“我已收到你的 SYN,现在确认这个初始报文段。”
    • 通常这个报文段长度为 0(不携带数据),仅用于完成连接建立。

这就是基本的三次握手过程:SYN -> SYN-ACK -> ACK


连接建立:同时打开 👐

TCP 还支持另一种建立连接的方式,称为“同时打开”。这在点对点应用中常用于穿越网络地址转换设备。

在同时打开中,双方都是主动发起方,并且都知道对方的端口号。其工作方式如下:

  1. 双方几乎同时向对方发送 SYN 报文段(seq = S_Aseq = S_P)。
  2. 双方在收到对方的 SYN 后,各自回复一个 SYN-ACK 报文段(seq = 自己的序列号+1, ack = 对方的序列号+1)。

此时,连接建立完成。双方都同步知晓了起始序列号,并确认了对方的 SYN。

请注意,同时打开需要交换 4 个报文段,而不是 3 个。


实战观察:Wireshark 抓包分析 🔍

现在让我们看看实践中的标准握手。以下是通过 Wireshark 抓取的一个访问 Web 服务器(端口 80)的 TCP 连接建立过程:

  1. Packet 1: [SYN]

    • 从客户端发往服务器。
    • 标志位:SYN=1
    • 显示序列号:0 (Wireshark 为方便阅读使用了相对序列号)。
    • 实际序列号:0xccbd1dbb (一个随机数)。
    • 确认号:无效 (因为 ACK=0)。
  2. Packet 2: [SYN-ACK]

    • 从服务器发往客户端。
    • 标志位:SYN=1, ACK=1
    • 显示序列号:0。
    • 实际序列号:0x3413135ae (另一个随机数)。
    • 确认号:0xccbd1dbc (客户端序列号 0xccbd1dbb + 1),表示确认收到了客户端的 SYN。
  3. Packet 3: [ACK]

    • 从客户端发往服务器。
    • 标志位:ACK=1
    • 显示序列号:1,确认号:1。
    • 这是一个长度为 0 的报文段,表示“我期待从字节 1 开始接收数据,但本包不携带数据”。

至此,一个简单的三次握手完成。随后,数据传输开始。例如,下一个数据包可能显示 [ACK],序列号为 1,负载长度为 474 字节,表明它正在发送实际的 HTTP 请求数据。


连接拆除:四次挥手 👋

与使用 SYN 位来同步序列号的连接建立不同,连接拆除使用 FIN 位来指示数据发送完毕。

当 TCP 发送一个包含 FIN=1 的报文段时,意味着发送方没有更多数据要发送(流结束)。但 TCP 连接是双向的,必须双方都完成数据发送并交换 FIN 后,连接才能完全终止。

典型的连接拆除(四次挥手)交换过程如下(假设 A 先发起关闭):

  1. FIN from A
    A 发送一个 FIN=1, ACK=1 的报文段,序列号为 seq = S_A,确认之前的数据。
  2. ACK from B
    B 收到后,发送一个 ACK=1 的报文段进行确认,ack = S_A + 1
  3. FIN from B
    一段时间后,B 也准备关闭,发送自己的 FIN=1, ACK=1 报文段,序列号为 seq = S_B
  4. ACK from A
    A 收到 B 的 FIN 后,发送最终的 ACK=1 报文段进行确认,ack = S_B + 1

注意:也存在双方同时发送 FIN 的“同时关闭”情况,其报文段交换逻辑类似。


连接拆除后的状态:TIME_WAIT ⏳

交换完 FIN 和 ACK 后,我们何时才能真正拆除连接、释放状态并重用端口呢?这并非立即进行。

考虑一个问题:如果最终的 ACK 在网络中丢失了会怎样?对方将永远不知道连接已成功关闭。另一个问题是,如果立即重用相同的端口对建立新连接,旧连接中延迟的报文段可能会干扰新连接。

TCP 的解决方案是引入 TIME_WAIT 状态。主动发起关闭的一方在发送完最后一个 ACK 后,会进入此状态,并等待一段时间(通常是 2 倍的最大报文段寿命,约 2 分钟),然后才完全关闭连接。

这确保了:

  1. 丢失的最终 ACK 可以有时间被重传。
  2. 旧连接的报文段有足够时间在网络中消逝。

对于需要处理大量短连接的服务器,长时间的 TIME_WAIT 可能成为性能瓶颈。因此,操作系统通常提供套接字选项(如 SO_REUSEADDR)来调整行为,但这需要谨慎使用。


实战观察:连接拆除抓包 🧹

让我们再看一个 Wireshark 抓取的连接拆除实例(接续之前的通信):

  1. Packet N: [FIN, ACK] from Client
    • 客户端发起关闭,设置 FIN=1, ACK=1
  2. Packet N+1: [ACK] from Server
    • 服务器确认客户端的 FIN。
  3. Packet N+2: [FIN, ACK] from Server
    • 服务器也发起关闭,发送自己的 FIN。
  4. Packet N+3: [ACK] from Client
    • 客户端确认服务器的 FIN。

随后,客户端进入 TIME_WAIT 状态。


完整的 TCP 有限状态机 🗺️

现在,我们把连接建立和拆除的所有状态组合起来,就得到了完整的 TCP 有限状态机。它看起来复杂,但可以清晰地分为两大部分:

第一部分:连接建立

  • CLOSED: 初始状态。
  • LISTEN: 服务器端被动打开后进入监听状态。
  • SYN_SENT: 客户端主动发送 SYN 后进入的状态。
  • SYN_RCVD: 服务器收到 SYN 并回复 SYN-ACK 后进入的状态。
  • ESTABLISHED: 连接建立成功,双方可进行数据传输。
    • 路径包括:标准三次握手、同时打开(四报文交换)。

第二部分:连接拆除

  • FIN_WAIT_1: 应用发起关闭,发送 FIN 后进入。
  • FIN_WAIT_2: 收到对方对己方 FIN 的 ACK 后进入(但未收到对方的 FIN)。
  • CLOSE_WAIT: 收到对方的 FIN 并发送 ACK 后进入(己方还未发起关闭)。
  • LAST_ACK: 在 CLOSE_WAIT 状态的应用也发起关闭,发送 FIN 后进入。
  • TIME_WAIT: 主动关闭方在发送完最终 ACK 后进入,等待 2MSL。
  • CLOSED: 最终状态,连接完全关闭,资源释放。

状态机虽然包含多达十一个状态,但理解其核心是建立同步有序结束两个阶段后,就会发现其逻辑是清晰且必要的。它奠定了 TCP 可靠连接的基础。


总结 📚

本节课中,我们一起深入学习了 TCP 连接建立与拆除的完整过程。

我们首先理解了在通信端点维护状态的重要性。接着,我们详细剖析了标准的三次握手(SYN -> SYN-ACK -> ACK)和四次挥手(FIN -> ACK -> FIN -> ACK)流程,并通过 Wireshark 抓包进行了实战观察。

我们还探讨了同时打开这种特殊情况,以及连接拆除后关键的 TIME_WAIT 状态的作用和意义。最后,我们将所有状态整合,俯瞰了TCP 有限状态机的全貌,认识到它如何严谨地管理着连接的整个生命周期。

建议你使用 Wireshark 工具,亲自抓取浏览网页时的 TCP 流量,直观地验证和巩固本节课所学的知识。

课程 P37:传输层协议回顾 📚

在本节课中,我们将回顾传输层协议的核心知识。我们将重点学习三种最重要的传输层协议:TCP、UDP和ICMP,并深入理解它们的工作原理、应用场景以及指导互联网设计的端到端原则。

概述 📖

传输层是网络协议栈中的关键一层,负责为应用程序提供端到端的通信服务。本单元主要探讨了三种广泛使用的传输层协议:TCP、UDP和ICMP。TCP提供了可靠的字节流传输服务,UDP提供了简单的无连接数据报服务,而ICMP则用于网络诊断和错误报告。此外,我们还学习了指导互联网设计的核心原则——端到端原则。

三种核心传输层协议 🔧

上一节我们介绍了本课程的整体目标,本节中我们来看看三种核心的传输层协议。

1. 传输控制协议 (TCP) 🌐

第一个是TCP,即传输控制协议。超过95%的互联网应用使用TCP,它几乎被普遍采用。这是因为TCP提供了几乎所有应用都希望的可靠的端到端的双向字节流服务

本单元的大部分内容都围绕TCP展开。我们学习了如何检测在传输途中丢失或损坏的数据包,并深入探讨了TCP用于成功重传数据的机制,直到数据被正确送达。我们花费了相当多的时间,探索了在不同不可靠的网络环境中实现可靠数据传输的各种方法。

2. 用户数据报协议 (UDP) 📦

我们研究的第二个传输层是UDP,即用户数据报协议。UDP被那些不需要TCP所提供的保证交付服务的应用程序使用。这可能是因为应用程序自身以私有的方式处理重传,或者是因为应用程序本身只需要尽力而为的交付。

UDP所做的只是获取应用数据,并创建一个UDP数据报。这个数据报标识出数据应该发送到的目标应用程序。在接收端,UDP也仅负责将数据递交给对应的应用。尽管使用UDP的应用相对较少,但我们看到了DNS(域名系统)和DHCP(动态主机配置协议)这两个典型的例子。它们都是简单的请求-响应查询协议。

3. 互联网控制消息协议 (ICMP) ⚠️

我们学习的第三个协议是ICMP,即互联网控制消息协议。ICMP的主要工作是在网络出现问题时发送反馈信息。例如,如果一台路由器收到了一个IP数据包,但却不知道下一步该将其发送到哪里,那么它会向数据包的源地址发送一条ICMP消息,通知源主机这个情况。

ICMP非常有用,它可以帮助我们理解为什么端到端的通信无法正常工作。

端到端原则 🧠

最后,你学习了指导互联网设计的最重要的总体架构原则之一,这个原则至今仍在引导我们的思考。它被称为端到端原则

我们学习了端到端原则的两个版本:

  • 温和版本:有些功能只能在网络的边缘(即端主机上)被正确、完整地实现。可靠的文件传输和安全就是两个我们见过的例子。虽然允许在网络内部添加功能来辅助这些特性,但这些辅助功能不能替代端到端的实现。
  • 强力版本:如果一个功能能够在端主机上实现,那么我们就应该这样做。其基本思想是网络本身应该保持简单、高效,尽可能减少内置功能,以避免引入错误、降低速度或需要频繁升级。这个原则假设端主机(如笔记本电脑或智能手机)足够智能,能够实现应用程序所需的许多功能。

本单元核心知识点总结 📝

在本单元中,我们主要学习了以下五个主题:

以下是本单元涵盖的五个主要知识点:

  1. 三种广泛使用的传输层
    • TCP:用于在应用程序之间可靠地传递字节流。
    • UDP:用于在应用程序之间不可靠地传递数据报。
    • ICMP:用于检测和报告网络错误。

  1. TCP的工作原理:我们特别强调了TCP如何可靠地在两个应用程序之间传递字节。你学习了如何检测数据错误和丢失的数据包,以及如何重传数据包。我们还探讨了几种不同的重传策略,包括选择性重传回退N帧。你学习了基本的TCP机制如何使用确认(ACK)和滑动窗口来跟踪已发送但未确认的字节。

  1. UDP的工作原理:我们解释了UDP如何工作,以及为什么它只被少数特定的应用程序使用。

  1. ICMP的工作原理:我们解释了ICMP如何工作,以及它如何帮助我们检测通信中断,并监控两个端主机之间的路由性能。

  1. 端到端原则:这是互联网设计以及本课程中涉及的许多其他通信系统的一个重要总体原则。在你进入业界并运用网络专业知识时,你会发现许多人会引用这个原则来指导他们的设计决策。

总结 🎯

本节课中我们一起学习了传输层的核心内容。现在,你应该对三种传输层协议(TCP、UDP、ICMP)有了很好的理解。你应该理解不同的数据包重传策略,以及TCP为什么使用滑动窗口机制。你也应该知道TCP为什么使用连接、连接是如何建立的,以及用于维护连接状态的有限状态机。这些知识是理解现代网络通信的基础。

课程 P38:分组交换入门 🧩

在本节课中,我们将要学习分组交换的核心概念。分组交换是现代互联网和几乎所有计算机网络的基础。我们将探讨其工作原理、优势以及它带来的关键挑战。


为什么需要分组交换? 🤔

上一节我们介绍了课程概述,本节中我们来看看分组交换的基本动机。

互联网以及几乎所有的现代网络都建立在分组交换的基础之上。分组交换在概念上很简单,因为它将每个分组视为一个数据的自包含单位。每个分组都包含了使它到达目的地所必需的信息。

分组交换在效率上的优势在于,它只在有工作需要完成时,才使用链路资源,而不是为每个用户或每个应用保留专用的容量。


分组交换的数学基础与延迟 📐

理解了基本概念后,我们将深入探讨分组交换带来的一些后果。本节的旅程将包含一些数学内容,这在本课程的其他单元中不常见。

数学可能在一开始看起来有些令人畏惧,但实际上它非常简单。一旦你掌握了这些数学工具,许多其他细节和复杂问题就变得非常容易回答和理解。

例如,你将学习到为什么在两个相同的源主机和目的主机之间旅行的两个数据包可能会遇到不同的延迟。尽管它们在每个物理链路上的传播时间可能相同,但数据包可能会走不同的路径,并在路由器的缓冲区中经历不同的排队延迟。

以下是数据包延迟的三个主要组成部分:

  1. 处理/排队延迟:数据包在路由器中等待处理和转发的耗时。
  2. 传播延迟:信号在物理介质(如光纤)中传输的耗时,计算公式为:延迟 = 距离 / 传播速度
  3. 传输延迟:将数据包的所有比特推送到链路上的耗时,计算公式为:延迟 = 数据包大小 / 链路带宽

到本单元结束时,你将理解导致这些延迟的物理过程。你将能够回答诸如“从这里到伦敦的数据包需要多长时间?”或“在月球和火星之间的通信链路上可以容纳多少个数据包?”之类的问题。


缓冲区与实时应用的挑战 ⏱️

上一节我们介绍了延迟的组成,本节中我们来看看路由器缓冲区的作用及其对应用的影响。

你将理解路由器为什么需要缓冲区,并了解排队延迟如何导致数据包到达时间的不确定性。对于大多数应用程序(如网页浏览、文件传输),这种不确定性不是一个大问题。

但对于需要实时回放*滑音视频的应用程序(如Skype和YouTube),它们必须应对互联网上变化的延迟。你将学习播放缓冲区是如何为解决这个特定问题而设计的。


路由器的工作原理 🔧

最后,你将了解分组交换机在实际工作中的工作原理。在本单元的末尾,你也将能够回答这个问题:互联网路由器实际上如何工作?

它与以太网交换机的区别在哪里?它是如何成为一个路由器的?其内部如何安排查找表?


总结 📚

本节课中,我们一起学习了分组交换的基础知识。我们从其基本概念和效率优势出发,探讨了数据包延迟的数学构成,理解了路由器缓冲区的作用及其对实时应用的挑战,并初步了解了路由器内部的工作原理。分组交换是互联网的基石,掌握这些概念是理解更复杂网络技术的关键。

课程 P39:网络与互联网简史 📜

在本节课中,我们将简要回顾人类远距离通信方式的演变,并了解现代互联网是如何从早期的通信网络中一步步发展而来的。我们将从古老的烽火信号开始,一直讲到万维网的诞生。

从烽火到信使:早期通信方式 🔥

上一节我们介绍了课程概述,本节中我们来看看人类最初的远距离通信方式。虽然今天我们能够轻松地向世界另一端发送电子邮件,但在三千年前,远距离通信极其困难,甚至根本不可能。有记录的最早远距离通信大约始于公元前一千年。

以下是几种主要的早期通信方式:

  • 烽火信号塔:这些塔楼主要为军事攻防目的设立。火炬被用来传递敌人来袭的信号或协调进攻。下图是英格兰南部的一个烽火信号塔示例。烽火传递信息迅速,尤其在夜晚危险最大时效果显著。但它们携带的信息量极少,通常只有“开启”(危险)或“关闭”(安全)两种状态。

  • 信使系统:数千年来,人类信使、马匹和信鸽在全球范围内被使用,因为它们可以携带更多信息。最早的记录传递系统出现在约两千年前的埃及和中国。例如,在十三世纪,成吉思汗的军队每隔约四十公里就设有一个驿站,备有马匹供信使接力。这种方式直到十九世纪仍被用于邮件递送,例如美国著名的驿马快信。然而,这些系统的信息传递速度比光慢,且沿途的信号和信使容易被拦截,消息可能被阅读、篡改或完全阻断。

光学电报的突破:编码与协议 📶

上一节我们了解了依靠人力和畜力的通信方式,本节中我们来看看利用光速传递信息的重大进步。大约两千年前,人们开始使用光学方法,例如旗帜和反光镜。

这些方法可以编码数字信息,如字母、单词和数字。这些系统能以光速在有限距离内传输有限的信息,本质上是简单的编码。但光学通信最大的进步发生在法国。

在1793年法国大革命期间,克劳德·夏普发明并开始建设一个名为“信号机”的光学电报网络。

克劳德·夏普建造了带有大型水*横梁(称为调节器)和两个较小臂杆(称为指示器)的塔。其形态类似一个人用双臂做出不同手势,臂杆的位置指示一个特定符号。1793年,法国政府建造了15座站点,覆盖190公里。到1804年,一个从巴黎延伸至第戎、长达370公里的网络形成。该系统用于发送各类消息,包括军事信息和新闻快讯。

为了使网络正常工作,法国的光学电报系统(以及瑞典的系统)发展出了许多至今仍在网络中使用的核心概念。以下是他们需要开发的五个关键概念:

  1. 代码:用于指示字符和控制信号的符号。例如,传输开始、传输结束、等待、冲突(当两个信号同时到达时)、错误取消、塔楼故障、确认,甚至表示“因雨或雾无法看清信号”。
  2. 流量控制:防止发送方数据过快淹没接收方。本质上是接收方告诉发送方“请减速,我跟不上了”。
  3. 同步:用于界定一个符号何时结束、下一个符号何时开始。这有助于定义由多个符号组成的单词。
  4. 错误纠正与重传:当接收方告知发送方符号被误解时,允许发送方尝试重新发送。
  5. 加密:确保消息无法被拦截。他们对股市新闻的泄露尤为担忧。

到1830年代,尖端的信号机网络已覆盖法国大部分地区。

通信网络的四个发展阶段 📈

上一节我们深入了解了光学电报的运作原理,本节中我们将其置于更宏观的通信网络发展史中来看。我们可以将通信网络的发明分为四个主要阶段:

  1. 约公元前至17世纪:人们开始使用系统发送一组预定义的消息,例如使用烽火。
  2. 16世纪起:人们开发了能够传输任意消息的系统,方法是对整个字母表进行编码。
  3. 17世纪初:数字代码开始用于表示常见的单词和短语。这是压缩的最早形式,因为它减少了链路上需要发送的信息量。
  4. 17世纪:为控制信号开发了代码。这些代码可以通信何时开始和停止发送、何时减速、如何重传等。这就是今天我们所说的协议的诞生。

到1800年,双方或多方如何通信的协议已达成共识。

在欧洲,多种不同的光学电报系统被开发和部署,使用了各种协议信号,例如:初始化信号(指示即将开始通信)、错误控制、重传、停止、等待、选择性重复(用于重传沿途损坏的数据)。这些概念与你在关于不同重传策略和流量控制的视频中所见非常相似。

电话的发明与互联网的萌芽 ☎️

上一节我们总结了通信网络的理论发展,本节中我们来看看推动现代通信的下一个重大发明。通信在19世纪末取得了巨大进步,当时电话被发明。此前,人们曾多次尝试增加连接美国许多城市的电报网络的容量。

图中展示的是亚历山大·格拉汉姆·贝尔,这位苏格兰裔发明家在1876年传输了第一次语音通话。尽管这项专利遭到了多次挑战(其中最具代表性的挑战者是另一位发明家伊莱沙·格雷),但它最终经受住了法律考验,我们通常将电话的发明归功于贝尔。十年内,超过150万人拥有了电话。到1915年,第一次从纽约到旧金山的跨大陆电话接通。

最终导致互联网诞生的一系列事件和发明进程从那时起开始加速。

阿帕网与互联网的诞生 🌐

上一节我们看到了电话如何连接大陆,本节中我们来看看计算机网络如何连接世界。大约在1960年,麻省理工学院的J.C.R. Licklider开始撰写备忘录并谈论他的“星际网络”概念。在这个网络中,全球各地的人们相互连接,可以从任何站点访问程序和数据。这被认为是对社交网络的第一次详细描述,并被认为可能由一个与当今互联网非常相似的大规模通信网络实现。

Licklider后来成为美国国防部高级研究计划局(DARPA)计算机研究项目的负责人。在DARPA期间,他说服了伊万·萨瑟兰德、罗伯特·泰勒和麻省理工学院的研究员拉里·罗伯茨关于其新网络概念的重要性。1964年,他们接过了这个重任。

  • 研究者保罗·巴伦撰写了现在被认为是关于大规模通信网络的第一篇学术论文《论分布式通信网络》。
  • 伦纳德·克莱因洛克撰写了关于队列理论的论文。
  • 英国国家物理实验室的唐纳德·戴维斯也在研究非常相似的想法。

1965年,拉里·罗伯茨与托马斯·梅里尔合作,通过低速电话调制解调器,将麻省理工学院的TX-2计算机连接到加利福尼亚的Q-32计算机,创建了第一个广域计算机网络。1966年,拉里·罗伯茨加入DARPA帮助开发第一个ARPANET计划。该计划于1967年发布。

1969年,第一台设备在加州大学洛杉矶分校、斯坦福研究所、加州大学圣塔芭芭拉分校和犹他大学安装,并通过ARPANET发送了第一条消息。这就是1969年互联网最初的样子,它被称为ARPANET,是一个封闭的私有网络。

协议标准化与万维网的黎明 💻

上一节我们看到了第一个计算机网络ARPANET的诞生,本节中我们来看看互联网如何通过协议统一并走向大众。到20世纪70年代初,许多不同的分组交换网络开始出现:

  • 1971年:第一个分组无线电网络在夏威夷群岛之间建立,称为ALOHAnet。其为ALOHA协议开发的机制影响了此后几乎所有的无线网络。
  • 1971年:法国建造了CYCLADES研究网络。它是第一个让终端主机负责可靠通信的网络,对互联网设计产生了重大影响。
  • 1974年:IBM引入了完整的数据网络协议栈SNA(系统网络架构),旨在降低构建大型分时计算机的成本。

DARPA赞助了对网状网络的研究,以创建第一个“网络的网络”(Internet)。互联网所需的核心协议首先由斯坦福大学的文特·瑟夫和DARPA的鲍勃·卡恩在1974年著名的论文《分组网络互联协议》中描述。最初的TCP要求可靠、按序的数据交付,并包含了今天我们所说的网络层的大部分功能。早期没有拥塞控制的概念,大约十五年后才被加入。到70年代末,TCP和IP被分离,为UDP作为不可靠传输服务(最初用于分组语音)留出了空间。

文特·瑟夫和鲍勃·卡恩在1983年被公认为“现代互联网之父”。TCP/IP在“旗日”首次在互联网上全面部署(即所有系统同时升级使用新协议)。1986年,美国国家科学基金会创建了NSFNET,以56kbps的链路连接全美各地的大学和超级计算机。其他小型网络开始涌现并连接到互联网。到80年代末,大约有10万台主机连接。

然后,大约在1990年,蒂姆·伯纳斯-李在欧洲核子研究中心发明了万维网(World Wide Web)。1993年,第一批网页浏览器出现,其中最著名的是马克·安德森编写的Mosaic浏览器。一年内,全球有超过1000万人使用网络。到90年代末,雅虎、谷歌、亚马逊等名字已家喻户晓。

如果你对网络和互联网的早期历史感兴趣,这里有三本非常值得推荐的参考书:

总结 📝

本节课中,我们一起学习了从古代烽火到现代互联网的通信发展简史。我们看到了人类如何从发送简单的预定义信号,发展到建立复杂的光学电报网络并发明了关键的通信协议概念。随后,电话的发明实现了实时语音通信。20世纪下半叶,计算机网络的兴起,特别是ARPANET的建立和TCP/IP协议的标准化,为全球互联的互联网奠定了基础。最终,万维网和浏览器的出现,使互联网走进了千家万户,彻底改变了人类社会信息获取与交流的方式。

课程 P4:互联网协议(IP)服务模型详解 🧩

在本节课中,我们将深入探讨互联网协议(IP)的服务模型。IP是互联网网络层的核心协议,负责将数据包从源主机发送到目的主机。我们将了解IP服务的关键特性、设计原则以及其数据包格式。


互联网协议(IP)概述

上一节我们介绍了互联网的四层模型,本节中我们来看看网络层,特别是互联网协议(IP)。对于许多人而言,IP就是互联网本身。每当我们在互联网上通信时,都需要使用IP来发送和接收数据包。

每层都为上一层提供服务。为了正确使用网络层,我们需要深入理解IP所提供的服务。


IP数据包的旅程

当传输层有数据要发送时,它会将一个传输段交给网络层。网络层将这个段放入一个新的IP数据包中。IP数据包由头部和一些数据组成,其核心任务是将数据包送达互联网另一端的接收主机。

首先,IP数据包必须通过第一条链路到达第一个路由器。因此,IP将数据包发送到链路层,链路层将其封装进一个链路帧(例如以太网帧)中,然后发送到第一个路由器。


IP服务的四个核心属性

IP服务的特性可以由以下四个属性来描述:

  1. 它是一个从源主机到目的主机的数据包投递服务。
  2. 它是不可靠的,但会尽最大努力传递数据包。
  3. 它是“尽力而为”的服务。
  4. 它不与数据包流相关联,是无状态的。

让我们逐一详细探讨这些属性。

1. 数据包投递服务

当我们要求IP发送数据时,它会创建一个数据包并将数据放入其中。数据包在网络中基于其头部信息被独立路由,因此它是自包含的。

以下是数据包头部包含的关键信息:

  • 目的地IP地址(IP DA):每个路由器的转发决策都基于此地址。
  • 源IP地址(IP SA):表示数据包来自何处,以便接收方知道如何回复。

数据包通过“逐跳”的方式在网络中路由,从源地址到目的地址。每个路由器都维护一个转发表,它根据数据包的目的地地址,决定将数据包转发到路径上的下一跳。

2. 不可靠的服务

IP不承诺数据包一定会被送达目的地。数据包可能迟到、顺序错乱、丢失,甚至在传输过程中被意外复制。

IP只会在必要时丢弃数据包,例如当路由器队列因拥塞而满时。它不会尝试重传丢失的数据包,甚至不会通知发送方数据包已被丢弃。

3. 无连接与无状态

IP服务是无连接的。这意味着IP层不会为一次通信(例如一次Skype通话)建立和维护端到端的状态。每个IP数据包都被独立、单独地路由,IP层对它们属于哪个“流”或“会话”一无所知。

4. 设计如此简单的原因

你可能会问,作为互联网的基石,IP为何设计得如此简单?主要有以下几个原因:

  • 保持网络简单:简单、最小化的网络可以更快、更便宜地构建和维护,也更容易使用专用硬件实现,从而更可靠。
  • 端到端原则:该原则主张,尽可能将功能(如可靠通信、拥塞控制)实现在通信路径的终点(即源主机和目的主机),而不是网络中。这确保了功能为应用程序正确实现,并更容易演进和改进。
  • 灵活性:简单的IP服务允许在其上构建各种可靠或不可靠的服务。例如,实时视频应用可能不希望重传丢失的数据包,而简单的IP正好提供了这种灵活性。
  • 链路层无关性:IP对底层链路层(如以太网、Wi-Fi)做出极少假设,因此它几乎可以在任何类型的链路上运行。这种设计使得互联网能够连接各种异构网络。

IP提供的其他关键机制

除了基本的“尽力而为”数据报服务,IP还提供了一些精心选择的机制,以*衡功能性与简单性。

以下是IP提供的五个重要特性:

  1. 防止数据包无限循环(TTL):IP在数据包头部包含一个生存时间(TTL)字段。该字段初始化为一个值(如128),数据包每经过一个路由器,TTL值减1。当TTL减至0时,路由器会丢弃该数据包,这防止了因路由错误导致的数据包在网络中无限循环。
    • 公式表示if (packet.ttl == 0) { discard(packet); }
  2. 分片:如果数据包太大,无法通过某条链路(如最大传输单元MTU较小的链路),路由器会将其分割成多个较小的IP数据包。IP头部中的标识、标志和分片偏移字段用于帮助接收端主机正确地重新组装原始数据包。
  3. 头部校验和:IP头部包含一个校验和字段,用于检测头部在传输过程中是否出错。这有助于减少因头部损坏而将数据包错误投递的机会。
  4. IP版本:目前主要使用两个版本:IPv4(使用32位地址)和IPv6(使用128位地址)。互联网正逐渐从IPv4向IPv6过渡。
  5. 可扩展的头部选项:IP允许在头部添加可选字段以支持新特性。但在实践中,为了保持转发路径的简单高效,路由器很少处理这些选项。

IPv4数据包头部详解

现在,我们来看一下当今最常用的IPv4数据包头部。理解每个字段的作用有助于你更清晰地把握IP服务模型的范围和其“故意简单”的设计哲学。

下图展示了IPv4头部的结构(以32位字为单位):

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options (if IHL > 5)                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

以下是各关键字段的说明:

  • 版本(Version):指明IP协议版本,对于IPv4,此值为4。
  • 头部长度(IHL):以32位字为单位指示IP头部的长度,因为头部可能包含可变长的选项字段。
  • 服务类型(Type of Service):为路由器提供关于此数据包优先级的提示。
  • 总长度(Total Length):指整个IP数据包(头部+数据)的长度,最大可达65535字节。
  • 标识、标志、分片偏移(Identification, Flags, Fragment Offset):这三个字段共同用于数据包的分片与重组过程。
  • 生存时间(Time to Live, TTL):如前所述,用于防止数据包无限循环。
  • 协议(Protocol):标识数据部分承载的上层协议(如TCP为6,UDP为17)。接收主机根据此字段将数据交给正确的处理模块。
    • 代码示例if (ip_header.protocol == 6) { pass_to_tcp(ip_packet.data); }
  • 头部校验和(Header Checksum):用于验证IP头部在传输过程中的完整性。
  • 源地址(Source Address):发送主机的32位IPv4地址。
  • 目的地址(Destination Address):接收主机的32位IPv4地址,是路由决策的核心依据。

总结

本节课中,我们一起学习了互联网协议(IP)的服务模型。我们了解到:

  • IP是互联网网络层的核心,提供从源到目的地的数据包投递服务。
  • IP服务是不可靠尽力而为无连接的,这是其保持简单、高效和灵活性的关键设计。
  • IP的设计遵循了端到端原则,将复杂性置于网络边缘的主机中。
  • 除了基本服务,IP还通过TTL分片校验和等机制提供了必要的健壮性保障。
  • IPv4头部的各个字段共同协作,实现了上述所有功能。

理解IP这种“简单而愚蠢”的服务模型,是理解更上层协议(如TCP如何构建可靠性)和整个互联网架构的基础。如果你对四层模型或IP的工作方式仍有疑问,建议回顾相关课程内容或查阅经典计算机网络教材。

计算机网络课程 P40:分组交换原理 📦

在本节课中,我们将要学习计算机网络中的一个核心概念——分组交换。我们将了解它的定义、工作原理,以及它为何成为互联网的基础技术。我们还会将其与另一种通信方式——电路交换进行对比,分析各自的优缺点。

概述:什么是分组交换?

分组交换最早由保罗·巴伦在二十世纪六十年代早期提出。它描述了信息包(即分组)如何像邮局递送信件一样,逐个通过互联网路由到目的地。选择分组交换决定了网络的许多属性。

背景:分组交换的前身——电路交换

在深入了解分组交换之前,我们先来看看它的前身:电路交换。我们都非常熟悉电路交换,因为它是传统电话网络中使用的方式。

电路交换的工作原理

在传统的电话网络中,当一部电话呼叫另一部电话时,会建立一个端到端的专用连接。这个连接在通话期间会一直保持,直到通话结束。

以下是电话通话的三个阶段:

  1. 建立:拿起听筒并拨打号码,电话系统尝试找到并连接被叫方。
  2. 通信:连接成功后,创建一条从一端到另一端的专用电路,声音被数字化并通过这条电路传输。
  3. 关闭:挂断电话后,电路被拆除,沿途所有交换机的状态被移除。

在现代数字电话系统中,城市之间的高速干线(如光纤)可以同时承载成千上万个独立的电话呼叫,每个呼叫占用自己独立的64kbps电路。

电路交换的特点总结

以下是电路交换的主要特征:

  • 每个呼叫都有其私有的、从端到端保证隔离的数据率。
  • 呼叫有三个阶段:建立、通信和关闭。
  • 电路最初是一条物理线,现在是由虚拟私有线组成,与别人共享物理线路但逻辑上独立。

电路交换的不足

尽管电路交换对电话系统工作得很好,但将其用于计算机通信时,存在一些不足:

以下是电路交换的三个主要问题:

  1. 效率低下:计算机通信往往是突发性的(例如,发送网页内容后会有阅读的暂停期)。在沉默期,专用电路被占用但未被使用,导致网络容量利用率低。
  2. 速率不灵活:计算机应用需要的数据速率差异巨大(从每秒几个字符到每秒数兆比特的视频流)。固定的速率电路无法适应这种多样性。
  3. 状态管理复杂:需要为每个呼叫在沿途所有交换机上建立和维护状态(入口到出口的电路映射)。如果发生故障,需要重新配置所有状态,管理负担重,且容易产生不一致。

分组交换的工作原理 🔄

上一节我们介绍了电路交换及其不足,本节中我们来看看分组交换如何工作。

在分组交换中,没有端到端的专用电路。数据被分割成一个个带有地址信息的“分组”,然后独立地在网络中传输。

分组交换的基本过程

假设左边的笔记本电脑要与右边的服务器通信。在分组交换中,通信过程如下:

  1. 发送方将数据块封装成分组,分组包含数据头部。头部中最重要的信息是目的地地址
  2. 分组被送入网络,由沿途的分组交换机(如路由器)根据其内部的转发表,逐跳地转发到目的地。
  3. 每个分组交换机查看分组的目的地址,查询转发表,决定将其发送到哪一个“下一跳”。

例如,一个分组的目的地址是 B。当它到达交换机 S1 时,S1 查询自己的转发表,发现地址 B 的下一跳是 S2,于是将分组发送给 S2S2 再根据自己的转发表,将分组转发给 S4,最终到达目的地。

分组交换机的关键组件

分组交换机(如路由器)内部有两个关键部分:

  • 转发表:用于查询每个分组应该被转发到哪个输出链路。
  • 缓冲区:用于临时存储分组。当多个分组同时到达并竞争同一个输出链路时,来不及发送的分组需要在缓冲区中排队等待。

分组交换的特点总结

以下是分组交换的主要特征:

  • 分组由路由器根据本地转发表单独路由
  • 所有分组共享链路的全部容量,突发流量可以高效利用带宽。
  • 路由器不维护每条通信的特定状态,只维护通用的转发表,简化了网络管理。

为何互联网选择分组交换? ✅

了解了分组交换的工作原理后,我们来看看它被选为互联网基础技术的核心原因。

以下是互联网选择分组交换的三个主要原因:

  1. 高效利用昂贵链路:互联网骨干链路最初带宽有限且昂贵。分组交换允许多个突发性的数据流高效地共享同一条链路,极大地提高了资源利用率。
  2. 坚韧性与容错性:由于每个分组被独立路由,且网络不维护端到端连接状态,当某条链路或路由器发生故障时,分组可以自动选择其他可用路径到达目的地,网络具有很强的生存能力。
  3. 互联异构网络:互联网最初的设计目标是连接各种已有的计算机网络。当时,大多数计算机网络都采用分组交换技术。为了与它们兼容,互联网自然选择了分组交换。

总结

本节课中我们一起学习了计算机网络的核心——分组交换。我们首先了解了其前身电路交换的工作原理和不足。接着,我们深入探讨了分组交换如何通过将数据封装成带地址的分组、并由交换机逐跳转发来实现通信。最后,我们分析了分组交换因其高效性、坚韧性和兼容性而被选为互联网基础技术的原因。

在接下来的课程中,我们将学习更多关于分组交换的知识,包括其基本定义、建模方法以及多年来发展出的各种特性。

课程P41:分组交换原理、术语、端到端时延与排队时延 🧩

在本节课中,我们将深入学习分组交换的核心概念。我们将定义传播时延和打包时延,并推导出数据包从源到目的地的总时延表达式。此外,我们还将探讨排队时延如何影响端到端时延的可预测性。


概述

分组交换是互联网的基础。在上一节视频中,我们介绍了分组交换是什么以及它为何被用于互联网。本节中,我们将深入探讨与分组交换相关的关键术语和时延计算,特别是端到端时延的构成。


传播时延

上一节我们介绍了分组交换的基本概念,本节中我们来看看第一个关键定义:传播时延。

传播时延是指一个比特在链路上以传播速度 c 从一端旅行到另一端所需的时间。观察下图,左边是发送端计算机,右边是接收端。一个比特从左到右所需的时间即为传播时延 t_l

传播时延 t_l 的计算公式为:

t_l = l / c

其中:

  • l 是链路的长度(单位:米)。
  • c 是传播速度(单位:米/秒)。

传播速度 c 通常接*光速。例如,在双绞线中,比特以约光速的70%传播;在光纤中则稍慢。在大多数计算中,我们假设 c = 2 × 10^8 米/秒。

请注意:传播时延仅取决于链路的物理长度和比特的传播速度,与链路的数据率无关。无论链路速率是1 Kbps还是10 Gbps,传播时延都相同。

示例:假设光纤长度为1000公里(1 × 10^6 米),传播速度 c = 2 × 10^8 米/秒。则传播时延为:
t_l = (1 × 10^6) / (2 × 10^8) = 0.005 秒,即5毫秒。


打包时延

理解了信号在介质中传播需要时间后,接下来我们看看将数据“装入”链路需要多长时间,这就是打包时延。

打包时延是指将数据包的第一个比特放入链路开始,到最后一个比特也被放入链路为止所花费的时间。

打包时延 t_p 的计算公式为:

t_p = p / r

其中:

  • p 是数据包的比特长度(单位:比特)。
  • r 是链路的数据率(单位:比特/秒)。

数据率 r 决定了我们向链路“注入”比特的速度。速率越高,打包时延越短。

请注意:打包时延仅取决于数据包的长度和链路的数据率,与链路的长度或传播速度无关。

以下是两个计算示例:

  1. 示例一:一个64字节(512比特)的数据包,在100 Mbps(1 × 10^8 bps)的链路上传输。
    t_p = 512 / (1 × 10^8) = 5.12 × 10^{-6} 秒,即5.12微秒。

  2. 示例二:一个1 Kibibit(1024比特)的数据包,在1 Kbps(1000 bps)的链路上传输。
    t_p = 1024 / 1000 = 1.024 秒。
    这里需要注意单位:网络通信中,数据包大小的“Kibit”通常指1024比特(2^10),而链路速率的“Kbps”通常指1000比特/秒。


端到端时延

现在我们已经掌握了两种基本时延,本节我们将学习如何计算一个数据包从源主机到目的主机的总时间,即端到端时延。

端到端时延是指从源主机在第一条链路上发送数据包的第一个比特开始,到目的主机接收到数据包的最后一个比特为止所经历的总时间。

在由多个存储转发路由器(交换机)构成的路径上,总时延是路径上每一段链路(或称“跳”)的时延之和。对于每一跳 i,其贡献的时延包括:

  1. 在该链路上的打包时延 p / r_i
  2. 在该链路上的传播时延 l_i / c

因此,不考虑排队时延的端到端时延 T 的表达式为:

T = Σ (p / r_i + l_i / c),对路径上的所有链路 i 求和。

让我们通过一个时间线图来详细理解这个过程。假设数据包从A经过交换机S1、S2到达B,穿越了三条链路:

  • 第一跳 (A -> S1)
    • 第一个比特需要 l1 / c 时间到达S1。
    • p / r1 时间后,最后一个比特被放入链路。
    • 在时间 l1/c + p/r1,整个数据包到达S1。S1作为存储转发设备,需要等待整个包到达后才开始处理并转发。
  • 第二跳 (S1 -> S2)
    • 重复类似过程。第一个比特需要 l2 / c 时间从S1到达S2。
    • 最后一个比特在 p / r2 时间后到达S2。
  • 第三跳 (S2 -> B)
    • 过程同上。

将每一跳的时延相加,就得到了总端到端时延。


排队时延

然而,上面的故事并不完整。在分组交换网络中,链路是被多个用户的数据包共享的。这就引入了端到端时延中的第三个,也是唯一不确定的组成部分:排队时延。

当多个数据包同时到达一个路由器,并希望使用同一个出站链路时,它们必须进行“竞争”。路由器内部设有包缓冲区(或队列)。数据包按照先到先服务的原则在队列中等待链路空闲。

排队时延 Q_i(t) 是指数据包在路由器 i 的队列中等待被转发的时间。这个时间值 t 表示它是一个随时间变化的量。

  • 缓冲区的作用:缓冲区可以避免在链路拥塞时立即丢弃数据包。缓冲区越大,丢包的可能性越低。
  • 排队时延的特性:排队时延是不确定的(非确定性的)。它取决于同一时刻网络中有多少其他用户也在发送数据,以及他们的流量模式。如果队列前面有N个包,你的包就需要等待大约 N * (p / r) 的时间。

因此,包含排队时延的、更完整的端到端时延表达式为:

T = Σ (p / r_i + l_i / c + Q_i(t))

在这个表达式中,只有 Q_i(t) 是随机变量,其他部分(打包时延和传播时延)都是确定的。


时延测量实例

为了让你确信端到端时延确实存在不确定性,我们可以进行实际测量。一个广泛使用的工具是 ping 命令,它测量的是往返时延(RTT),即数据包从源到目的地再返回源的总时间,这大致是单向端到端时延的两倍。

以下是两个测量示例:

  1. 从斯坦福到普林斯顿大学(约4000公里)
    • RTT值大约在100毫秒左右。
    • 测量值的波动范围(方差)较小,约90%的样本落在100-120毫秒之间。这表明路径相对稳定,排队时延影响较小。
  2. 从斯坦福到清华大学(约10000公里)
    • RTT值显著增加,大约在200毫秒以上,这是因为传播距离大大增加。
    • 关键发现:RTT样本的变异性(波动范围)急剧增大,可达200毫秒。这是因为数据包在更长的路径上经过更多路由器,遇到其他用户流量和网络拥塞的可能性更高,从而导致排队时延变化巨大。在这个例子中,排队时延几乎占了总时延的一半。

这些测量直观地展示了排队时延如何成为端到端时延中不可预测且有时占主导地位的部分。


总结

本节课中,我们一起学习了分组交换网络中端到端时延的三个决定性组成部分:

  1. 传播时延:由链路物理长度 l 和传播速度 c 决定,计算公式为 t_l = l / c
  2. 打包时延:由数据包长度 p 和链路数据率 r 决定,计算公式为 t_p = p / r
  3. 排队时延:由路径上路由器缓冲区的拥塞程度决定,记为 Q_i(t),它是端到端时延中唯一不确定的随机变量。

完整的端到端时延表达式为:T = Σ (p / r_i + l_i / c + Q_i(t))

排队时延的不确定性对实时应用(如语音、视频通话)有重要影响,我们将在下一个视频中探讨其后果。

课程P42:分组交换原理 - 播放缓冲区 🎬

在本节课中,我们将学习实时应用(如流媒体视频)如何处理网络中可变的排队延迟。我们将重点介绍播放缓冲区的概念,了解其工作原理以及如何通过它来吸收延迟变化,从而保证流畅的用户体验。


播放缓冲区的作用

上一节我们介绍了端到端延迟的计算及其不稳定性。本节中我们来看看,对于实时应用而言,这种延迟的变异性为何至关重要。

我们使用的大多数应用并不特别关心端到端延迟的变异性。例如,下载网页或发送电子邮件时,我们希望尽快完成,但不介意单个数据包花费10到12毫秒到达。

但有些应用必须关心排队延迟,特别是实时应用,如流媒体视频和语音。在接下来的内容中,我们将解释排队延迟如何使这些应用变得困难。这可以作为排队延迟的一个好例子,并解释我们如何在实践中缓解此问题。

应用无法确切知道数据包何时到达,因此不能保证能够按时向用户交付所需的语音或视频样本。为此,它们会在一个称为播放缓冲区的地方积累数据包。

播放缓冲区的直观认识

你可能已经见过播放缓冲区。下图是YouTube客户端底部的一个小截图。剩余的部分显示我们已经看过的视频,这里的播放点表示我们当前观看的位置。灰色线条部分显示了已经缓冲但尚未播放给用户的视频数据包,这就是我们感兴趣的播放缓冲区

客户端故意构建这个播放缓冲区,试图领先一步,以防止一些数据包被延迟或无法按时到达,从而避免播放中断。

设计播放缓冲区时,我们必须考虑希望缓冲区领先多远。如果我们将缓冲区构建得很大,就可以吸收更多的数据,并容忍更大的队列延迟变化。如果缓冲区非常短,当队列延迟出现大幅变化或突然增加时,我们可能会耗尽数据包,因为它们可能无法按时出现。因此,设计播放缓冲区对于应用正常工作至关重要。

播放缓冲区的详细分析

让我们更详细地分析播放缓冲区。下图展示了我们正在播放的点,以及我们已经缓冲的数据量。

这是播放缓冲区的内容。我们以此为例进行设置:想象我们在右侧的笔记本电脑上观看YouTube视频,它从左侧的YouTube服务器流式传输视频。

我们假设视频以 1 Mbps(每秒1兆比特) 的速率流式传输。这只是一个示例数字,实际速率可能不同。数据包将通过路径中的多个路由器(图中标记为1、2、3),实际路径中的路由器可能多达10到15个。

我们主要关心的是路径中的队列延迟。这里有三个可能经历队列延迟的地方,这种可变的队列延迟意味着数据包到达时间略有不可预测。

数据发送与接收的累积图

下面的图表显示了服务器随时间累积发送的字节数。由于它以恒定的1 Mbps速率发送,这条线是直的。累计发送的位数或字节数随时间线性增长:一秒后发送100万位,十秒后发送1000万位。

由于网络中的可变队列延迟,笔记本电脑上的累计到达量看起来不同,可能像图中这样一条弯曲的线。

这意味着,如果我们取第一个到达的字节(按到达顺序),可以水*画一条线,查看特定字节何时到达。X轴表示特定字节从发送到接收所花费的时间。

注意,这里使用“位”和“字节”,但单位并不重要。如果我们取图中任意一点(例如某个特定字节),水*画一条线,该线与X轴的交点即该字节到达笔记本电脑的时间。因此,延迟由水*距离测量,并且这个距离是变化的,取决于每个数据包遇到的队列延迟。

我们还可以看到,在任意给定时间,路径上缓冲的数据量(即从服务器发出但尚未被客户端播放的字节数)由图中的垂直距离显示。因为它表示在特定时间已发送的数量与已接收的数量之差。

从这张图中我们可以获取很多信息。横轴表示延迟,纵轴表示网络中当前缓冲的字节数。

延迟的界限与约束

让我们回到我们的例子。延迟的最大组成部分是传播延迟打包延迟,这些是固定部分。因此,我们对这个线段的形状有相当的了解。实际的形状可能非常不同,但我刚刚创造了这个形状来说明。

首先我们知道一些事情:从开始到结束的总延迟不能少于传播和打包延迟,这是一个下限。因此,图中两条线之间的水*距离有一个下限。

它也有一个上限:路由器中的缓冲区大小是有限的。因此,任何数据包可能经历的最大延迟是它通过所有路由器缓冲区时的排队延迟之和,再加上打包延迟和传播延迟。这代表了一个上限。

但上限并不非常有用,因为它可能非常大。在实际应用中,路由器可能具有半秒的缓冲,如果我们经过多跳,下限和上限之间可能存在巨大差异,因此这对我们几乎没有用。

我们还知道右侧的累计到达量是非递减的。换句话说,这个值总是增加,因为它是接收到的字节总数,显然不能出现负的字节数。

最后我们还知道一件事:因为我们知道最后一段链路的速率有一个上限(可能是100 Mbps或1 Gbps),它告诉我们瞬时到达率(即图中到达曲线的斜率)不能超过该链路的数据速率。

客户端的工作机制

有了所有这些限制,让我们来看看客户端需要采取哪些步骤才能使这一切工作。

图中的红色线显示了视频向用户的播放速率。这告诉我们,在某个时间点,它正在播放服务器发送的第一个字节(当然,这也是接收器接收的第一个字节)。

如果我们在这里取一条水*线,它将告诉我们一个特定字节被发送、接收然后播放的时间。这意味着这里的水*距离告诉我们一个特定的字节已经被缓冲了多久。因此,在任何时间我们都可以知道一个字节在播放缓冲区中停留了多长时间才被播放。

我们还知道播放缓冲区中有多少字节:它是图中在任意时间的垂直距离,这告诉我们播放缓冲区的占用情况

我们可以看到,开始时播放缓冲区非常小,然后逐渐积累,在这里达到了一个非常大的值,随后随着播放进度落后,缓冲区变小,几乎变空。我们非常幸运,因为有些字节可能后来才出现,我们只是避免了缓冲区耗尽。然后,在某个时候,我们又积累了一些缓冲区。

我们以恒定的1 Mbps速率回放,这就是用户听到的内容。这是一个好的例子:我们选择了正确的值,等待了足够长的时间,积累了足够的缓冲,最终一切顺利。

客户端的内部结构

在客户端内部,它大致看起来像这样:播放缓冲区是客户端内存中持有的一个缓冲区。客户端正在选择播放点,即我们在YouTube客户端上看到的那个点。字节从播放缓冲区中取出后,被放入视频解码器,转换回视频,然后在屏幕上播放。

缓冲区不足的情况

让我们来看看事情不太顺利的情况。同样的例子再次出现:服务器在左侧发送字节,笔记本电脑在右侧接收字节。但在这种情况下,我们等待播放第一个字节的时间不够长。

你可以在这里看到,我们从接收到第一个字节到开始播放的等待时间稍微短了一些。当然,一旦我们开始播放字节,我们就必须承诺以1 Mbps的速率播放它们,否则无法在屏幕上持续显示视频。

对于这个特定情况,一开始一切看起来很好,缓冲区占用率良好。但它变得越来越小,直到最终到达一个点,我们遇到了问题:缓冲区变空。这意味着我们没有任何可以解码并显示在屏幕上的字节。图中所有的红色区域都是我们处于“赤字”的时间,这很不好。

客户端做得好的是(我们都见过这种情况):它必须使缓冲区更大。它通过重新缓冲来实现这一点,即冻结屏幕,等待一些字节积累,然后才能继续播放。

如果你一直在慢速链接上观看这个视频,或者你距离很远,数据包需要通过许多路由器,你可能经历过这种缓冲事件。你可以通过以更低的速率流式传输视频,或者简单地提前下载视频来解决这个问题。

总结与回顾

总的来说,在带有缓冲区的播放中,当我们进行端到端的分组交换时,延迟是可变的。我们使用播放缓冲区来吸收这种变化。

我们可以使播放缓冲区非常大,但那样视频在开始时会有延迟(即我们等待第一个字节到达直到播放的时间)。如果我们使缓冲区更大,就必须延迟视频的起始点,这在观看视频时会带来不便。

因此,应用程序试图估计延迟。它们试图估计从服务器到笔记本电脑的延迟,设置播放点,然后如果延迟发生变化,则调整缓冲区大小。

现在让我们回到对端到端延迟的原始表达式。现在我们看到,它由以下三个部分组成:

  1. 打包延迟
  2. 传播延迟
  3. 可变的队列延迟

队列向路径添加了可变和不可预测的延迟。

课程总结 🎯

本节课中我们一起学习了:

  • 端到端延迟由三个部分组成:
    • 传播延迟:比特在链路上传播所需的时间(固定)。
    • 分组延迟:将分组放入链路所需的时间(固定)。
    • 队列延迟:数据包在路径上路由器的缓冲区中等待的时间(可变)。
  • 一些应用(如流媒体视频)使用播放缓冲区来吸收可变的队列延迟,帮助应用以固定的速率将视频流回给用户。
  • 播放缓冲区的设计需要在启动延迟抗抖动能力之间进行权衡。

这就是分组交换原理中关于播放缓冲区的内容。在接下来的课程中,我将介绍一个简单的确定性模型,帮助我们更好地理解这些概念。

📦 课程 P43:分组交换原理 - 简单确定性队列模型

在本节课中,我们将继续学习分组交换,并重点探讨几种不同的队列模型。我们将从一个简单的确定性队列模型入手,理解其动态过程,并学习如何利用这种模型来分析网络中的队列延迟、数据包化对延迟的影响以及统计复用的概念。


🧠 理解队列模型:一个简单的确定性视角

上一节我们介绍了分组交换的基本概念,本节中我们来看看如何用一个简单的模型来描述路由器队列的行为。这个模型有助于我们直观理解网络拥塞时队列的动态变化。

我们可以将一个路由器的输出队列想象成一个“桶”。数据包(或字节)像水一样流入这个桶,并以一个固定的速率从桶中流出(即通过输出链路发送出去)。

  • A(t):表示到时间 t 为止,累计到达队列的字节数。
  • D(t):表示到时间 t 为止,累计从队列离开的字节数。
  • r:输出链路的固定服务速率(单位:字节/秒)。
  • q(t):在时间 t,队列中暂存的字节数,即队列的占用率。其计算公式为:
    q(t) = A(t) - D(t)

通过绘制 A(t)D(t) 随时间变化的累积曲线图,我们可以直观地看到:

  1. 任何时刻 t 的队列长度 q(t),就是两条曲线在 t 时刻的垂直距离。
  2. 一个在时刻 t 到达的字节所经历的排队延迟 d(t),就是该字节对应的 A(t)D(t) 之间的水*距离(假设队列遵循先进先出 FIFO 原则)。

这个简单的图形化工具为我们分析队列行为提供了强大的直觉。


📊 应用示例:计算*均队列占用率

理解了模型的基本形式后,我们通过一个具体例子来看看如何应用它。

问题设定:

  • 数据包以每秒 1 个的间隔到达。
  • 每个数据包长度为 100 位。
  • 数据包到达速率为 1000 位/秒(即发送一个包需 0.1 秒)。
  • 队列的输出链路速率 r 为 500 位/秒。

求解:队列的*均占用率是多少?

分析与解答:
我们可以分析一个周期(1秒)内的队列行为:

  1. 在第一个 0.1 秒内,数据包以 1000 位/秒的速率到达,但只能以 500 位/秒的速率离开。因此,队列在此期间以 1000 - 500 = 500 位/秒的速度累积。
  2. 0.1 秒后,数据包到达完毕,队列开始以 500 位/秒的速度清空。清空累积的 100 位数据需要 100 / 500 = 0.2 秒。
  3. 因此,在一个 1 秒的周期内,队列有数据的时间为 0.1 + 0.2 = 0.3 秒,空闲时间为 0.7 秒。

在队列有数据的 0.3 秒内,其占用率从 0 位线性增长到 100 位,再线性下降回 0 位。因此,*均队列占用率可以计算为:
*均占用率 = (0.5 * 100位 * 0.3秒) / 1秒 = 15位

这个例子展示了如何利用确定性模型分析队列的基本性能指标。


⏱️ 数据包化如何减少端到端延迟

在了解了单个队列的行为后,我们将视角扩展到整个网络。你可能会问,为什么要把消息拆分成多个小数据包?一个关键原因是为了降低端到端延迟。

考虑一个长度为 M 位的消息需要穿越多个路由器。

  • 方案A:不拆分。整个消息作为一个大“包”发送。在第一个链路上传输时,后续链路必须等待,无法并行工作。
  • 方案B:拆分。将消息拆分为多个长度为 P 位的小数据包(P < M)。第一个小包在第一个链路上传输后,可以立即开始在第二个链路上传输,而此时第一个链路正在传输第二个小包。

这种流水线(管道)传输效应,使得多个链路可以同时工作,从而显著减少了消息的端到端总延迟。尤其是在消息很长、网络路径很长的情况下,将消息分包的收益非常明显。端到端延迟的*似公式为:
总延迟 ≈ (M/P) * (P/R1 + P/R2 + ...) + 各链路传播延迟之和
其中 Ri 是第 i 条链路的速率。通过减小 P,可以增加流水线的并行度。


🔀 统计复用:共享链路的高效利用

最后,我们探讨分组交换的另一个核心优势:统计复用。它允许多个数据流高效地共享同一条物理链路。

想象一个路由器,有 N 条输入链路(速率均为 r)和一条输出链路(速率也为 r)。如果所有输入链路同时满速率发送,输出链路将无法处理,必然导致丢包。但现实中,数据流的到达通常是突发且不规律的。

统计复用增益 就来源于这种不规律性。多个流同时达到峰值的概率较低,因此它们的总*均到达速率可能远低于 N * r。只要这个*均速率低于输出链路的速率 r,网络就能正常处理。即使短时间内总速率超过 r,路由器中的缓冲区也可以暂时存储多余的数据包,*滑流量波动。

因此,统计复用使得我们能够用一条链路承载多个数据流,提高了链路资源的整体利用率。这是分组交换网络效率远高于传统电路交换网络的重要原因之一。


📝 课程总结

本节课我们一起学习了分组交换中的几个核心模型与概念:

  1. 简单的确定性队列模型:我们学会了如何用累积到达/离开曲线来建模和分析队列的动态,包括计算队列长度和排队延迟。
  2. 数据包化的优势:我们明白了将大消息拆分为小数据包可以通过流水线传输的方式,有效降低网络中的端到端延迟。
  3. 统计复用:我们了解了多个数据流如何通过共享链路和利用缓冲区来高效地利用网络资源,这是分组交换的基石之一。

掌握这些基本原理,将帮助你更好地理解复杂网络的行为和性能。

排队论基础教程 P44:一个简单的排队模型示例 📊

在本节课中,我们将通过一个具体的工作示例,学习排队论中的基本概念,包括队列占用率、*均延迟以及随机到达对系统的影响。我们将使用简单的数字和图表来阐明这些概念。

概述 📋

本教程将分析一个特定的排队场景:数据包(比特流)以特定速率到达一个队列,并以较慢的速率离开。我们将计算队列的*均占用率、比特的*均延迟,并探讨当到达模式变得随机时,系统性能会发生什么变化。

问题设定与参数 🔧

首先,我们明确示例中的系统参数。

以下是系统的基本设定:

  • 到达过程:在每个“秒”的开始时刻,有100比特的数据到达队列。这意味着到达速率 λ = 1000比特/秒(因为100比特在0.1秒内到达)。
  • 服务过程:队列的服务(离开)速率是 μ = 500比特/秒
  • 服务规则:数据按比特(bit-by-bit)进行服务,这意味着无需等待整个数据包到达,比特就可以开始离开。
  • 缓冲区:假设缓冲区容量是无限的。

我们的目标是分析这个系统的行为。

累积到达与离开过程 📈

上一节我们设定了系统参数,本节中我们来看看累积到达过程 A(t) 和累积离开过程 D(t) 是如何随时间演变的。

以下是两个过程的演变描述:

  • 在第一个0.1秒内,A(t) 以1000比特/秒的速率线性增长,在 t=0.1 秒时达到100比特。
  • t=0.1 秒后,没有新的比特到达,因此 A(t) 保持为100比特的水*线。
  • 离开过程 D(t) 在比特开始到达后立即开始。由于服务速率是500比特/秒,D(t) 以该速率线性增长。
  • 由于到达速率是离开速率的两倍,队列会开始堆积。在 t=0.1 秒时,到达停止,此时队列中的比特数达到最大。之后,队列开始以500比特/秒的速率排空。

计算队列*均占用率 🧮

了解了累积过程后,我们可以计算队列长度 Q(t),它定义为 Q(t) = A(t) - D(t),即任意时刻 t 在队列中等待的比特数量。

以下是队列占用率的计算过程:

  1. 0 ≤ t ≤ 0.1 秒期间,比特持续到达。队列长度从0开始增长,在 t=0.1 秒时达到峰值。峰值比特数为:100比特(到达的总比特) - 500比特/秒 * 0.1秒(离开的比特) = 50比特
  2. 0.1 ≤ t ≤ 0.2 秒期间,没有新比特到达,队列以500比特/秒的速率排空。队列长度从50比特线性下降到0比特。此期间的*均队列长度为 (50 + 0) / 2 = 25比特
  3. 0.2 ≤ t ≤ 1.0 秒期间,队列为空,长度为0比特。

现在,我们计算在一个完整的1秒周期内的时间*均队列占用率。系统以25比特的*均占用率运行了0.1秒,然后以0比特的占用率运行了0.8秒。

时间*均占用率公式为:
(0.1秒 * 25比特 + 0.8秒 * 0比特) / 1秒 = 2.5比特

因此,队列的*均占用率是 2.5比特

计算比特的*均延迟 ⏳

上一节我们计算了队列的占用情况,本节中我们来看看比特在队列中经历了多长的等待时间(延迟)。一个在时刻 t 到达的比特的延迟,是 D(t) 曲线超过 A(t) 曲线的水*距离。

以下是关于延迟的分析:

  • t=0 时刻到达的第一个比特无需等待,延迟为0。
  • t=0.1 时刻到达的最后一个比特,需要等待队列中它之前的所有比特被服务。由于队列中有50个比特,服务速率为500比特/秒,因此它的延迟是 50比特 / 500比特/秒 = 0.1秒
  • 比特的到达时间在0到0.1秒之间均匀分布。因此,所有到达比特的*均延迟是 (0秒 + 0.1秒) / 2 = 0.05秒

所以,比特在队列中的*均延迟是 0.05秒

随机到达的影响 🎲

现在,我们考虑问题的一个变体:如果100比特的“数据列车”不是定期到达,而是以随机间隔到达(*均每秒一列),那么*均队列占用率会如何变化?

结论是:与定期到达相比,随机到达会导致更高的*均队列占用率

以下是原因分析:

  • 在定期到达的案例中,两列数据从未在时间上重叠。前一列数据完全离开后,后一列数据才到达。这避免了队列的额外堆积。
  • 在随机到达的情况下,两列数据有可能在时间上发生重叠。即,前一列数据还未离开完毕,后一列数据就已经到达。这会导致队列中同时存在来自多列数据的比特,从而使队列长度增加,排空所需的时间也更长。
  • 即使重叠只是偶尔发生,它也会显著增加时间*均队列长度。因为队列“非空”的时间段变长了,并且在这些时间段内的*均队列长度也更高。

简单来说,随机性引入了“拥堵”的可能性,从而恶化了系统性能。

串联队列分析 ⛓️

最后,我们考虑一个两级串联队列系统:第一个队列的输出作为第二个队列的输入。第二个队列的服务速率也是500比特/秒。

以下是分析过程:

  • 第一个队列的输出过程(即离开过程 D1(t))的*均速率是500比特/秒。因此,第二个队列的到达过程*均速率也是 λ2 = 500比特/秒
  • 第二个队列的服务速率是 μ2 = 500比特/秒
  • 在这种情况下,*均到达速率等于*均服务速率(λ2 = μ2)。对于这种确定性的、规则化的到达流(经过第一个队列后,输出流被*滑了),第二个队列将不会积累比特。它的*均占用率将为 0

需要注意的是,这个结论依赖于“比特按比特服务”的假设,它使得第一个队列的输出流是*滑的。如果服务是以数据包为单位的,情况会更为复杂。

总结 🎯

本节课中我们一起学习了一个简单的排队模型示例。

我们首先定义了系统的到达率和服务率,并通过分析累积到达和离开过程,计算出了队列的时间*均占用率(2.5比特)和比特的*均延迟(0.05秒)。随后,我们探讨了随机到达如何通过引入数据流重叠的可能性,导致*均队列占用率升高。最后,我们分析了一个两级串联队列,发现当第二个队列的到达率等于其服务率且到达流规则时,其*均占用率为零。

这个示例清晰地展示了排队论中到达过程、服务过程与系统性能(如占用率和延迟)之间的基本关系。

📊 课程 P45:排队模型特性

在本节课中,我们将继续学习分组交换,并探讨排队模型的一些核心特性。我们将了解突发性如何影响延迟,学习一个重要的通用关系式,并认识泊松过程及其在网络建模中的应用。


🧠 排队模型概述

上一节我们介绍了分组交换的基本概念。本节中,我们来看看如何用排队模型来分析网络中的延迟。

我们可以将网络视为由许多队列组成的集合,这些队列通过链路连接。来自众多用户的流量或数据包在这些链路上汇聚,使得数据包的到达过程变得非常复杂。

因此,我们通常将到达过程视为随机事件。虽然每个数据包的生成是确定的,但聚合后的到达过程可以看作一个随机过程。理解具有随机到达过程的队列如何工作对我们非常有益。

在像网络这样的系统中,到达过程很复杂,所以我们经常使用随机过程来建模它们。研究具有随机到达过程的队列被称为排队论。排队论以数学复杂而闻名,但这些具有随机到达过程的队列有一些非常有趣的特性,能帮助我们理解网络的动态行为。


📈 特性一:突发性增加延迟

首先,我们来探讨第一个特性:突发性倾向于增加延迟。我们通过一个直观的例子来理解。

假设有一个最简单的到达过程:数据包以精确的每秒一个的固定间隔到达,完全没有随机性。同时,服务(数据包离开)的机会也是每秒一次。

在这种情况下,队列占用率 Q(t) 要么是0,要么是1。*均队列占用率在0和1之间。

现在,考虑一个更具突发性的场景:到达率仍然是*均每秒一个包,但数据包以突发形式到达。例如,每5秒到达5个包,然后安静5秒。服务机会仍然是每秒一次。

虽然*均到达率和离开率相同,但队列占用率现在可以在0到5之间变化。这意味着*均队列占用率和占用率的方差都增加了。

核心结论:即使*均速率不变,到达的突发性也会导致更高的*均队列长度和更长的延迟。


⏱️ 特性二:确定性最小化延迟

与第一个特性密切相关的是第二个特性:确定性倾向于最小化延迟

这本质上是第一个特性的反面。它表明,在相同的*均到达率下,完全确定性的、周期性的到达过程所产生的*均等待时间,比任何随机到达过程都要短。

换句话说,随机性(不确定性)本身就会引入额外的延迟。


🔗 特性三:Little 定律

在讨论第四个特性之前,我们需要了解一个强大而通用的结果:Little 定律

对于任何稳定的排队系统(即没有数据包丢失),都存在一个简单的关系。设:

  • λ 为*均到达率(例如,数据包/秒)。
  • L 为系统中顾客(数据包)的*均数量(包括正在排队和正在被服务的)。
  • D 为顾客(数据包)在系统中经历的*均延迟。

Little 定律指出:

L = λ * D

这个看似简单的结果适用于任何排队系统,只要系统稳定且有明确的*均到达率 λ。它不依赖于到达过程的具体形式或服务时间的分布。

应用:我们可以利用这个公式进行转换计算。例如,如果我们测量出*均队列长度 L 并知道到达率 λ,就可以估算出*均延迟 D。这个定律在后续分析中会非常有用。


📊 泊松过程简介

在介绍第四个特性前,我们需要了解一个重要的随机过程模型:泊松过程

泊松过程是一种常见的到达过程模型。如果一个到达过程是泊松过程,那么:

  1. 在长度为 t 的时间间隔内,恰好有 k 个事件(数据包)到达的概率由一个特定的公式给出(涉及参数 λ)。
  2. 连续到达之间的时间间隔是相互独立的。
  3. 在间隔 t 内到达事件数的期望值是 λt,其中 λ 是*均到达率。

为什么泊松过程重要?

  • 建模聚合事件:它能很好地模拟大量独立随机事件的聚合,例如电话呼叫到达交换机、放射性原子衰变等。
  • 数学简便:尽管定义公式可能看起来复杂,但它使得后续的排队分析数学上相对简单,因此被广泛使用。

重要警告:然而,网络中的数据包到达通常不是泊松过程。实际的网络流量具有显著的突发性,数据包常常成群到达,前后数据包之间并不独立。泊松过程更适合建模新通信流的开始(如新的网页请求),而不是聚合后的数据包流本身。因此,使用基于泊松的模型时需要格外小心。


🧮 特性四:M/M/1 队列模型

基于泊松过程,一个最经典和简单的排队分析模型是 M/M/1 队列

  • 第一个 M 代表马尔可夫(Markov)到达过程,这里即泊松到达。
  • 第二个 M 代表马尔可夫服务过程,这里指服务时间服从指数分布。
  • 1 代表只有一个服务器(例如,一条出站链路)。

由于其假设(泊松到达、指数服务时间),M/M/1队列的数学分析相对简单,并能给出直观的结果。

核心公式
对于一个M/M/1队列,数据包通过系统的*均延迟 D 为:

D = 1 / (μ - λ)

其中:

  • μ 是服务率(例如,链路每秒能发送的数据包数)。
  • λ 是到达率(λ < μ 系统才能稳定)。

*均队列长度 L 可以通过 Little 定律得出:

L = λ * D = λ / (μ - λ)

关键洞察
从公式可以看出,当负载 ρ = λ/μ 趋*于1时,分母 (μ - λ) 趋*于0,导致*均延迟 D 和*均队列长度 L 急剧增加,趋向于无穷大。这形象地展示了当系统接*饱和时,延迟会爆炸性增长。

虽然真实的网络队列并非严格的M/M/1,但这个简单模型能为我们提供关于延迟与负载关系的重要直觉。


📝 本节总结

本节课我们一起学习了排队模型的四个核心特性:

  1. 突发性增加延迟:数据包到达的突发性会导致更长的队列和更高的延迟,即使*均速率不变。
  2. 确定性最小化延迟:周期性的、确定的到达过程能产生最小的*均延迟。
  3. Little 定律:这是一个通用关系式 L = λ * D,连接了*均队列长度、*均到达率和*均延迟。
  4. M/M/1 队列模型:这是一个基于泊松到达和指数服务时间的简化分析模型,其公式 D = 1/(μ - λ) 揭示了延迟随负载增加而急剧上升的特性。

我们还认识了泊松过程,它是一个重要的数学模型,适用于描述许多独立事件的聚合,但需注意网络数据包到达本身通常不是泊松过程

理解这些特性有助于我们定性地分析网络性能,并理解延迟产生的根本原因。

计算机网络课程 P46:分组交换 - 交换与转发实践 (1) 🔄

在本节课中,我们将继续学习分组交换的主题,具体探讨分组交换机(如以太网交换机和互联网路由器)的工作原理、内部结构以及核心的地址查找机制。


通用分组交换机结构 🏗️

上一节我们介绍了分组交换的基本概念,本节中我们来看看一个通用分组交换机的内部结构和工作流程。

分组交换机处理数据包通常包含三个主要阶段:

  1. 地址查找:当数据包到达时,首先查看其目的地址,通过查询转发表来确定数据包应该从哪个出口链路或端口发出。
  2. 头部更新:根据需要进行头部字段的更新。例如,互联网路由器需要减少TTL(生存时间)并重新计算校验和。
  3. 排队与转发:将数据包放入输出端口的缓冲区中排队,等待在出口链路上发送。这是因为多个数据包可能同时竞争同一个出站链路。

一个典型的分组交换机拥有多个输入和输出端口。数据包从输入端口进入,经过上述处理后,会通过一个共享的内部交换结构(如总线)被传送到正确的输出端口队列。如果多个数据包目的地相同,它们将在输出队列中缓冲,依次发送。


以太网交换机 🖧

了解了通用结构后,我们具体看看以太网交换机是如何工作的。以太网交换机是专门处理以太网帧的分组交换机。

以太网交换机必须执行以下四个基本操作:

以下是其工作步骤:

  1. 检查帧头:检查每个到达帧的以太网目的地址。
  2. 查表转发:若目的地址存在于转发表中,则将帧转发到对应的输出端口(或多个端口,如广播情况)。
  3. 广播未知帧:若目的地址不在转发表中,则向除接收端口外的所有其他端口广播该帧。
  4. 学习地址:通过检查到达帧的以太网源地址来学习并填充转发表。当交换机首次看到某个源地址的帧从某个端口进入时,它就知道未来发送给该地址的帧应从该端口转发。

其转发表查找基于精确匹配。例如,一个表项可能如下所示:

目的地址: 00:1A:2B:3C:4D:5E -> 转发端口: 7

查找时,交换机通常使用哈希表来快速匹配48位的MAC地址。


互联网路由器 🌐

接下来,我们对比学习另一种重要的分组交换机——互联网路由器。路由器处理的是IP数据包,其操作比以太网交换机更复杂。

互联网路由器需要执行以下七个基本操作:

以下是其处理IP数据包的步骤:

  1. 检查帧目的地址:确认到达的以太网帧的目的MAC地址是否属于本路由器。若不是,则丢弃。
  2. 检查IP版本:检查IP头部的版本号是否为4(IPv4)。
  3. 处理IP头部:减少TTL值,并据此更新IP头部校验和。
  4. 检查TTL:若TTL减为0,则丢弃数据包。
  5. 查找路由表:根据IP目的地址查询路由表,执行最长前缀匹配,以确定下一跳和出口端口。
  6. 重新封装:将IP数据包封装进一个新的以太网帧中。
  7. 解析下一跳地址:通过ARP等协议,找出下一跳路由器接口的MAC地址,并将其作为新以太网帧的目的地址。

地址查找机制 🔍

无论是交换机还是路由器,地址查找都是核心操作。我们已经看到,以太网交换机使用精确匹配,而互联网路由器使用最长前缀匹配

最长前缀匹配详解

在IP路由中,地址不是单个主机地址,而是代表一个网络范围的前缀。例如:

  • 前缀 65.0.0.0/8 匹配所有第一个八位组为65的IP地址。
  • 前缀 128.9.0.0/16 匹配所有前16位为128.9的IP地址。

当一个目的IP地址同时匹配多个前缀时,路由器会选择前缀长度最长(即最具体)的那条路由。例如,地址 128.9.16.14 同时匹配 128.9.0.0/16128.9.16.0/24,但会选择更长的 128.9.16.0/24 作为匹配项。

实现方式

实现最长前缀匹配的两种常见数据结构是:

以下是两种关键技术:

  1. 二叉线索树:一种树形结构,根据IP地址的每个比特位(0或1)决定遍历左子树或右子树。树中的节点可以存储路由前缀信息。查找时,从根节点开始逐位匹配,最终找到最长匹配的前缀。

    示例:对于前缀 0/1(二进制0...),会存储在左子树根部。
    
  2. 三态内容可寻址存储器:一种特殊的硬件存储器。它将路由表项存储为(值,掩码)对。查找时,TCAM能并行地将输入地址与所有表项进行比较,并返回匹配的、掩码最长的表项。这种方法速度极快,但功耗较高。

    表项示例:
    值: 128.9.16.0
    掩码: 255.255.255.0  (表示前24位需要匹配)
    

通用化视角:匹配-动作范式 ⚙️

现代分组交换设备(交换机、路由器、防火墙等)的功能可以抽象为一个通用的匹配-动作范式。

  • 匹配:可以基于数据包头的任意多个字段(如MAC地址、IP地址、端口号等)。
  • 动作:可以是转发、丢弃、修改字段、封装等。

这种抽象使得设备能够灵活地支持多种网络功能,而不仅仅是二层交换或三层路由。


总结 📚

本节课中我们一起学习了分组交换的核心实践操作。

我们首先剖析了通用分组交换机的三个处理阶段:地址查找头部更新排队转发。接着,我们深入探讨了两种典型设备:以太网交换机基于MAC地址进行精确匹配查找和转发;互联网路由器则基于IP地址进行更复杂的最长前缀匹配查找。最后,我们介绍了实现高效查找的二叉线索树TCAM技术,并将分组交换的核心抽象为通用的匹配-动作范式。

下一节,我们将继续学习分组交换的另一个关键环节:数据包在交换机内部是如何被交换到正确输出端口的。

计算机网络课程 P47:包交换实践 - 交换与转发(2)🚀

在本节课中,我们将继续学习包交换器的工作原理。我们将重点探讨包交换器在完成地址查找后,如何将数据包切换到正确输出端口的不同技术。我们将了解输出队列、输入队列以及虚拟输出队列这三种核心交换架构,并分析它们各自的优缺点。


上一节我们介绍了包交换器如何通过查找转发表来确定数据包的去向。本节中,我们来看看如何将数据包实际切换到正确的出口端口。

包交换器在确定数据包的目标端口后,需要将其传输到对应的输出端口,以便通过正确的出站链路发送。这个过程被称为“交换”或“转发”。

输出队列交换机 📤

最简单的交换架构是输出队列交换机。在这种设计中,数据包在通过交换背板后,会在输出端口处排队等待发送。

以下是其工作流程:

  1. 数据包到达交换机,其头部信息(如颜色所示)指示目标输出端口。
  2. 交换逻辑将数据包通过内部背板发送到对应的输出端口。
  3. 如果输出链路繁忙,数据包将在该端口的输出队列中缓冲,并按照先进先出(FIFO)的顺序等待发送。

这种架构的主要挑战在于对缓冲内存速度的要求极高。在最坏情况下,所有 n 个输入端口的数据包可能同时要发往同一个输出端口。这意味着:

  • 写入队列的速率可能高达 n * rr 为端口速率)。
  • 而从队列读取的速率仅为 r

因此,输出端口的缓冲内存需要能以 (n+1) * r 的聚合速率运行。对于端口数量 n 很大的交换机,这限制了其可扩展性。

输入队列交换机 📥

为了解决输出队列对内存速度的苛刻要求,一种自然的思路是将队列从输出端移动到输入端,这就构成了输入队列交换机

以下是其工作流程:

  1. 数据包到达输入端口后,先在输入队列中缓冲。
  2. 交换调度器决定哪个输入队列的数据包可以通过背板发送。
  3. 只有当前输出链路空闲时,对应目标端口的数据包才能被发送。

这种设计的优势在于,每个输入端口的缓冲内存只需处理本端口的流量。其读写速率从 (n+1) * r 降低到了 2 * r,大大降低了对内存速度的要求,提高了交换机的可扩展性。

然而,输入队列交换机面临一个关键问题:队头阻塞

队头阻塞问题与虚拟输出队列 🚧

在基本的输入队列交换机中,每个输入端口只有一个FIFO队列。当一个数据包因为目标端口繁忙而阻塞在队头时,即使它后面数据包的目标端口是空闲的,这些数据包也无法被发送。这种因队头数据包阻塞而影响后续无关数据包传输的现象,就是队头阻塞。

队头阻塞会显著降低交换机的吞吐量。理论分析表明,在最坏情况下,其最大吞吐量可能降至约 58%

为了解决队头阻塞,业界广泛采用了虚拟输出队列 技术。

以下是VOQ的工作原理:

  1. 在每个输入端口,为每一个输出端口都维护一个独立的队列。
  2. 数据包到达时,根据其目标端口被放入对应的虚拟输出队列中。
  3. 调度器可以查看所有输入端口上所有VOQ的队头,并灵活地调度那些目标端口空闲的数据包进行传输。

因为去往不同端口的数据包被物理隔离在不同的队列中,所以一个队列的阻塞不会影响其他队列。这使得调度器能更充分地利用交换背板,理论上可以将吞吐量重新提升至 100%

VOQ的一个现实类比是道路上的专用转向车道(如左转车道)。直行车辆不会因为前方有等待左转的车辆而被阻塞,这类似于VOQ避免了去往不同“输出端口”(方向)的“数据包”(车辆)相互阻塞。

性能对比与总结 📊

让我们总结一下这三种交换架构的关键特性:

  • 输出队列交换机:性能最优(工作保守,吞吐量最大,延迟最小),但对内存速度要求极高,可扩展性差。
  • 输入队列交换机:内存要求低,可扩展性好,但受队头阻塞影响,吞吐量可能严重下降。
  • 虚拟输出队列交换机:在保持输入队列低内存要求的优点的同时,通过为每个输出维护独立队列,有效消除了队头阻塞,使吞吐量接*输出队列的水*。

下图展示了不同架构下,数据包*均延迟随负载变化的趋势:

  • 输出队列能实现最佳性能曲线。
  • 基本输入队列因队头阻塞,在负载较高时性能急剧下降。
  • 虚拟输出队列的性能则非常接*输出队列。

本节课中我们一起学习了包交换的三种核心转发架构。我们了解到,包交换器在完成地址查找后,需要通过内部交换结构将数据包送达正确端口。输出队列性能最好但成本高;输入队列更可扩展但存在队头阻塞问题;而虚拟输出队列 则是一种优秀的折中方案,它结合了可扩展性与高性能,因此在现代高速交换机中被广泛采用。理解这些基础架构,是深入认识网络设备内部工作原理的关键一步。

课程P48:包交换原理 - 速率保证 🚦

在本节课中,我们将学习先进先出(FIFO)输出队列的缺点,并探讨两种能够提供更好流量控制的替代方案:严格优先级交换机和提供速率保证的交换机。


FIFO队列的缺点

上一节我们回顾了包交换机的基本工作原理。现在,我们专注于输出队列,并分析当它采用FIFO(先进先出)规则时会产生哪些问题。

FIFO队列有时被称为“所有输入的免费竞争区”。如果流向该队列的流量来自多个输入源,那么在任何发生拥塞的时刻,数据包都会在这个FIFO队列中排队。发送速率最高的流将获得输出链路的最大使用份额。

这意味着,如果某个流能够以高速率发送大量数据包,它就可能独占输出链路,而其他低速率的流则可能被完全“挤出”,几乎无法获得服务。这种行为模式鼓励了“不良行为”——每个流都倾向于尽可能快地发送数据包,以最大化自己获得的带宽份额,这对网络整体是不友好的。

此外,FIFO队列无法区分数据包的重要性。无论是紧急的控制流量、重要的视频数据还是普通的背景流量,都按照到达的先后顺序被处理。这可能导致低延迟要求的流量(如实时视频)因为排队在后面而经历高延迟。

关于FIFO队列,有一个有用的观察:如果一个数据包成功进入队列,它在队列中等待的最长时间是 B / R,其中 B 是队列容量(以比特为单位),R 是出站链路的服务速率(比特/秒)。这个最大延迟界限在后续分析中会用到。


两种替代方案概述

鉴于FIFO队列的上述问题,本视频将描述两种替代方案:

  1. 严格优先级:为特定流量提供更高的优先级。
  2. 速率保证:为每个流保证一定的输出链路带宽份额或速率。

本质上,我们将把之前简单的单一队列替换为更复杂的调度机制。


方案一:严格优先级 🥇

在严格优先级方案中,我们将单一队列替换为一个高优先级队列和一个低优先级队列。

当数据包到达时,交换机会根据其包头中的信息(例如IP头中的“服务类型”字段)决定将其放入高优先级队列还是低优先级队列。分类的依据可以是:

  • 视频流量比电子邮件更重要。
  • 网络控制流量比普通数据流量更重要。
  • 付费用户的流量比普通用户的流量更重要。

以下是其工作原理:

  1. 数据包根据分类被放入相应的队列。
  2. 调度器始终优先服务高优先级队列中的数据包。
  3. 只有当高优先级队列为空时,调度器才会服务低优先级队列。

结果:高优先级流量完全“看不到”低优先级流量的存在,仿佛拥有一个私有网络。这对于需要绝对优先级的流量(如关键控制信令)非常有效。

潜在问题:如果高优先级流量过大,它可能长时间独占链路,导致低优先级流量被“饿死”(完全得不到服务)。因此,严格优先级通常只在高优先级流量相对较少的场景下使用。目前许多交换机和路由器都支持此功能。


方案二:加权公*队列与速率保证 ⚖️

如果我们不希望总是严格偏好某个队列,而是希望为不同流量分配成比例的、有保障的带宽份额,就需要更精细的调度机制。例如,我们希望队列1获得的带宽是队列2的两倍。

目标与模型

我们的目标是实现加权公*。假设有 N 个队列,每个队列 i 被赋予一个权重 w_i。那么,在出站链路总速率 R 中,队列 i 应获得的保证服务速率 R_i 为:

R_i = (w_i / Σ(w_j)) * R (公式中 j 从1到 N

如果所有数据包长度相同,实现起来就很简单:我们可以进行“轮询”服务,每轮依次访问每个队列,并从队列 i 发送 w_i 个单位的数据(可以是比特或完整数据包)。这样,长期来看,每个队列获得的服务比例就与其权重成正比。

挑战:可变长数据包

然而,实际网络中数据包长度是可变的(例如从64字节到1500字节不等)。如果我们按完整数据包来服务,长数据包会占用更长的发送时间,从而破坏权重的比例关系。我们必须考虑包长,以防止长包挤占短包。

解决方案思想:按位公*的模拟

我们引入一个思想实验:假设我们可以按比特服务数据包。我们以“轮次”为单位,每轮中,队列 i 可以发送 w_i 比特。当一个数据包的最后一个比特被服务后,这个完整的包才被认为“完成”并准备发送。

关键问题是:在按包发送的实际系统中,我们应该以什么顺序发送这些完整的包,才能最接*按比特服务的理想公*状态?

答案是:按照数据包在按比特服务模型下计算的完成时间来排序和发送。

完成时间的计算与WFQ调度

  1. 定义:设数据包 k 的长度为 L_k,它所属队列的权重为 w。如果按比特服务,它开始服务的轮次为 S_k,那么其完成轮次 F_k 为:
    F_k = S_k + L_k / w
    (因为每轮它获得 w 比特的服务)。

  2. 递归计算:当一个新数据包 k 到达时,它的开始时间 S_k 取决于队列中前一个包 k-1 的完成时间 F_{k-1},以及它到达时队列是否为空。我们可以取两者中的最大值:
    S_k = max(到达时间, F_{k-1})
    然后,用上面的公式计算其完成时间 F_k

  3. 调度决策:调度器维护每个队列队首数据包(即下一个要发送的包)的完成时间 F。每次需要发送数据包时,调度器总是选择所有队列中具有最小 F 值(即最早在理想比特模型中完成)的那个数据包进行发送

这种算法被称为加权公*队列(Weighted Fair Queuing, WFQ),也称为包基的广义处理器共享(PGPS)。

WFQ的优势

可以证明,在WFQ调度下:

  • 每个队列 i 实际获得的长时期*均服务速率 R_i 无限接*其保证速率 (w_i / Σw_j) * R
  • 每个数据包在实际包系统中离开的时间,与其在理想比特模型中完成的时间之差,不会超过 L_max / R,其中 L_max 是网络中的最大可能包长。

这意味着WFQ不仅提供了良好的长期带宽保证,也控制了短期内的延迟抖动。


总结 📝

本节课我们一起学习了包交换中输出队列调度的核心原理。

  1. FIFO队列 简单但存在缺点:它不区分流量优先级,无法提供速率保证,并且可能鼓励流为争夺带宽而采取激进发送策略。
  2. 严格优先级 通过引入高、低优先级队列,确保高优先级流量(如控制信令)获得即时服务,不受低优先级流量影响。但需注意避免低优先级流量被饿死。
  3. 加权公*队列(WFQ) 是一种更精细的调度算法。它通过为每个队列分配权重,并按照数据包在理想按比特服务模型下的完成时间(F_k)进行调度,从而为每个流提供有保障的、成比例的带宽份额。WFQ有效地实现了速率保证,并改善了公*性。

理解这些队列调度机制,是掌握网络服务质量(QoS)和流量管理基础的关键。

课程 P49:分组交换原理 - 延迟保证 🕒

在本节课中,我们将学习如何为分组交换网络提供端到端的延迟保证。我们将探讨如何控制队列延迟,并介绍实现这一目标的关键技术。


概述

在之前的课程中,我们了解到队列延迟是变化的。然而,通过特殊的技术,我们可以为数据包从网络一端到另一端的传输提供延迟保证。这些技术依赖于加权公*队列


端到端延迟方程

首先,回顾端到端延迟方程。该方程描述了数据包从网络一端到另一端的延迟,它是以下分量的函数:

  • 包化延迟:固定分量,等于包长度除以传输速率。
  • 传播延迟:固定分量,等于链路长度除以光速。
  • 队列延迟:可变分量,通常不受我们直接控制。

公式表示为:
端到端延迟 = (包长度 / 速率) + (链路长度 / 光速) + 队列延迟

为了提供端到端延迟保证,我们需要控制路径上每个路由器的队列延迟。


控制单个路由器的延迟

上一节我们介绍了端到端延迟的构成,本节中我们来看看如何控制单个路由器的队列延迟。

基本思想是:如果我们知道路径上每个队列延迟(q1, q2, q3...)的上限,那么整体端到端延迟也就有了上限。

在路由器内部,通过加权公*队列,我们可以为特定队列分配一个保证的服务速率 R1。如果我们同时知道该队列缓冲区的大小 B,那么数据包通过该路由器的最大延迟就被限制为 B / R1

核心概念

  • 服务速率 R1 由 WFQ 权重决定:R1 = (队列权重 / 所有权重之和) * 链路总速率 R
  • 最大队列延迟:D_max ≤ B / R1

因此,通过选择缓冲区大小 B 和利用 WFQ 控制服务速率 R1,我们可以控制单个路由器的延迟。


防止数据包丢失

仅仅控制延迟还不够。如果队列缓冲区溢出导致数据包被丢弃,就无法实现真正的“保证”。因此,我们必须确保缓冲区不会溢出。

以下是实现这一目标的关键思路:

我们使用一个简单的确定性队列模型来分析。累积到达过程 A(t) 和累积离开过程 D(t) 之间的垂直距离代表队列占用 Q(t),水*距离代表延迟 d(t)。

为了防止溢出,我们需要确保在任何时间间隔 T 内,到达的比特数不超过 B + R1 * T。其中 B 是缓冲区大小,R1 是服务速率。

如果这个条件始终满足,那么队列永远不会溢出,且最大延迟 d_max 也受限于 B / R1。


流量整形:漏桶算法

那么,如何确保数据流满足“在任何时间间隔 T 内,到达量 ≤ B + R1 * T”这个条件呢?答案是通过流量整形

一种广泛使用的技术是 σ-ρ 调节,其中 σ 代表允许的突发量(对应缓冲区大小 B),ρ 代表长期*均速率(对应服务速率 R1)。满足此约束的流量称为“σ-ρ 调节”流量。

在实践中,常用漏桶算法来实现 σ-ρ 调节。其工作原理如下:

  1. 令牌以固定速率 ρ 生成,并存入一个容量为 σ 的令牌桶中。
  2. 数据包到达时,必须从桶中取出等同于其大小的令牌才能被发送。
  3. 如果令牌不足,数据包必须等待或缓存。

漏桶机制确保了输出流量符合 σ-ρ 约束,即长期速率不超过 ρ,且最大突发量不超过 σ。


端到端延迟保证系统

现在,我们将所有部分组合起来,构建一个完整的端到端延迟保证系统。

  1. 流量源端:使用漏桶调节器对发出的流量进行整形,使其符合约定的 (σ, ρ) 参数。
  2. 网络路径上的每个路由器
    • 使用加权公*队列为该流量对应的队列分配保证的服务速率 R_i(需满足 R_i ≥ ρ)。
    • 为该队列配置足够大的缓冲区 B_i(需满足 B_i ≥ σ)。
  3. 延迟计算:端到端总延迟是固定延迟(包化延迟+传播延迟)与所有路由器队列延迟上限之和。每个路由器的队列延迟上限为 B_i / R_i

通过这种方式,只要流量源遵守约定,网络就能提供有上限的端到端延迟保证。像 RSVP(资源预留协议) 这样的协议就是用来在端到端之间协商和设置这些参数(σ, ρ, R_i, B_i)的。


实例分析

让我们通过一个例子来具体了解如何计算。

目标:一个应用希望以 10 Mbps 的速率发送 1 KB 的数据包,并要求端到端延迟小于 5 ms。

  1. 计算固定延迟
    • 包化延迟:根据链路速率分别计算 1 KB 数据包在每条链路上的传输时间,然后求和。
    • 传播延迟:总路径长度 (120 km) / 光速 (2e8 m/s)。
    • 假设计算出的总固定延迟为 0.97 ms。

  1. 分配队列延迟预算

    • 可用于队列的总延迟 = 5 ms - 0.97 ms = 4.03 ms。
    • 假设路径上有 2 个路由器,为简化,将延迟预算*均分配,每个路由器允许的最大队列延迟 D_max ≈ 2.015 ms。
  2. 计算路由器所需缓冲区大小 B

    • 已知服务速率 R1 = 10 Mbps,最大延迟 D_max = 2.015 ms。
    • 所需缓冲区大小 B ≥ R1 * D_max = 10e6 bps * 2.015e-3 s ≈ 20150 bits ≈ 2.46 KB。
    • 因此,每个路由器需要为该流量队列配置至少约 2.5 KB 的缓冲区。

通过以上设计和配置,可以满足端到端延迟小于 5 ms 的要求。


总结与现状

本节课中,我们一起学习了为分组交换网络提供延迟保证的原理:

  1. 通过加权公*队列控制队列的服务速率。
  2. 通过设置合适的缓冲区大小,并结合服务速率,可以限制单个队列的延迟。
  3. 通过漏桶调节器对流量进行整形,防止其超过约定参数,从而避免缓冲区溢出和数据包丢失。
  4. 将上述机制结合,并在整条路径上协调实施,即可提供有上限的端到端延迟保证

需要指出的是,尽管这种理论是完备的,但在实际互联网中并未大规模部署。因为它需要全网设备(运营商、路由器)的协同工作,实施复杂。目前,互联网主要依靠流量优先级过载控制的组合来为关键应用提供“足够好”的服务质量。

然而,理解这些原理对于深入掌握网络队列动力学至关重要,并且这些思想可能在未来的新型网络(如确定性网络)中得到应用。

课程P5:数据包的一天 📦

在本节课中,我们将学习一个数据包在互联网中从发送到接收的完整旅程。我们将了解互联网四层模型如何协同工作,并观察数据包在实际网络中的传输路径。


互联网四层模型概述 🌐

上一节我们介绍了课程主题,本节中我们来看看数据包传输的理论基础。

互联网的四层模型从应用层接收一个数据流。传输层将数据流分解为可靠的数据段,并将其送达运行在另一台计算机上的应用。传输层将这些段作为网络层包发送。网络层负责将这些包送达另一台计算机。


传输层与TCP连接 🤝

上一节我们介绍了网络分层,本节中我们来看看传输层的具体工作。

让我们看看这在实际中的样子:一个Web浏览器和服务器发送和接收的实际包。首先,让我们看看传输层。几乎所有的Web流量都是通过TCP(传输控制协议)传输的。在其典型操作中,有一个客户端和一个服务器。

服务器监听连接请求以打开连接。客户端发出连接请求,服务器对此做出响应。这种交换需要三个消息,被称为“三步握手”。

以下是TCP三步握手的过程:

  1. SYN:客户端向服务器发送同步消息。
  2. SYN-ACK:服务器响应同步消息,同时也确认了客户端的同步。
  3. ACK:客户端响应以确认服务器的消息。

所以常常将三次握手描述为:SYN, SYN-ACK, ACK。

网络层负责将数据包送达计算机。但是,传输层负责将数据送达同一台计算机上的应用程序。这意味着要向另一个程序打开TCP流,我们需要两个地址。

以下是建立TCP连接所需的两个关键地址:

  • IP地址:网络层用于将数据包送达计算机的地址。
  • TCP端口:告诉计算机软件将数据交付给哪个应用程序(例如,Web服务器通常运行在TCP端口80)。

因此,当我们连接到Web服务器时,我们将IP数据包发送到运行Web服务器的计算机(目的地IP地址),并且这些IP数据包内的TCP分段的目的地端口为80


网络层与路由器转发 🚦

上一节我们了解了如何建立端到端的连接,本节中我们来看看数据包在网络中是如何被转发的。

但那些IP数据包如何到达目的地?我没有直接线路将我的客户端连接到服务器。然而,我的客户端连接到一个中间电脑——一个路由器。这个路由器本身连接到其他路由器。客户端和服务器之间的IP包需要经过多个“跳转”。一个跳转是指路由器之间的连接。

因为我的客户端在一个Wi-Fi网络中,第一个站点(第一个跳转)是无线的,连接到Wi-Fi接入点。接入点通过有线连接到更广泛的互联网。所以,它为我的包开辟了道路。我客户端的数据包沿着这条有线跳点传输。

路由器可以有许多连接到它自身的链路。每当一个数据包到达,路由器将决定将其发送到它的哪个链路上。路由器自身也有IP地址,因此,也有可能它不会转发一个数据包,而是将其交付给它自己的软件(例如,当你登录路由器管理界面时)。

路由器如何做出这个决定?它通过一个被称为“转发表”的东西来实现,如图右所示。

以下是转发表的工作原理:

  • 转发表由一组IP地址模式组成,并对每个模式指定一个用于转发的链路。
  • 当数据包到达时,路由器检查哪个转发表条目的模式最匹配该数据包的目的IP地址。
  • 路由器将数据包沿着该匹配条目指定的链路转发。

一般意味着最具体的匹配最好。但在这个简单的例子中,让我们只考虑“默认路由”(表格上的第一个条目)。默认路由是最不具体的路由,它匹配所有有效的IP地址。如果当一个数据包到达时,没有比默认路由更具体的路由,路由器将使用默认路由。

默认路由在边缘网络中尤其有用。例如,斯坦福大学通过路由器连接到更大的互联网。该路由器会为斯坦福内部的IP地址设置许多具体路由(如发送到工程学校、图书馆)。但是如果目的地IP地址不在斯坦福内部,那么路由器就会使用默认路由,将其发送到更大的互联网。


实战观察:使用Wireshark抓包 🔍

上一节我们介绍了路由原理,本节中我们通过工具来实际观察数据包的流动。

现在让我们来看看网络中的一些真实IP数据包。我将从 www.brown.edu 请求一个网页,并使用一个称为 Wireshark 的工具来显示所有数据包。

我们将看到我的Web浏览器如何与布朗大学的Web服务器建立TCP连接(使用SYN-SYN-ACK的三次握手),然后它开始发出HTTP GET请求,服务器对此做出响应。

首先,我会启动Wireshark。因为我的电脑正在使用许多网络应用并发送大量不同的数据包,我会告诉Wireshark只显示到布朗服务器的TCP分段(使用端口80),这样我们只会看到我生成的Web流量。我还会告诉Wireshark监听 en0(这是我的Mac的Wi-Fi链路层接口名称)。

然后,我会打开网页浏览器并请求布朗大学计算机科学部门的网页。

在Wireshark中,加载此页面涉及发送和接收大量的包。Wireshark显示每个包的时间戳、源IP地址、目的地IP地址、使用的协议及其长度等进一步信息。

让我们看看第一个包:

  • 它来自我的电脑(IP: 192.168.0.106),发往布朗的CS Web服务器(IP: 128.148.32.12)。
  • 它试图连接到TCP端口80(服务器的HTTP端口)。
  • 从Info列可以看到,这个数据包是 SYN 包,即三步握手的第一步。

看前三个数据包:

  1. 第一个是从我电脑到Web服务器的 SYN
  2. 第二个是从Web服务器回到我电脑的 SYN-ACK 响应包。
  3. 第三个是从我电脑回到Web服务器的 ACK 响应。

这就是TCP三次握手的三个IP数据包。现在,两台电脑可以交换数据。你可以看到,紧接其后的数据包是一个 HTTP GET请求。对这个GET请求的响应是多个数据包,Wireshark在接收到足够数据时会将其识别并显示为“HTTP/1.1 200 OK”。

我们可以看到,从我的电脑请求布朗大学计算机科学服务器的网页,需要先通过三个IP数据包完成TCP三次握手,然后使用更多的数据包进行HTTP请求和响应。


实战观察:使用Traceroute追踪路径 🗺️

上一节我们看到了端点的数据交换,本节中我们来看看数据包在网络内部的路径。

这就是网络从终端(托管计算机)角度看起来的样子,当他们在网络层交换数据包时。但网络层内部看起来什么样子?这些数据包需要经过多少“跳”才能到达?为了看到这个,我将使用第二个工具:traceroute

Traceroute 显示数据包到达目的地所经过的每一跳(路由器)。我们可以输入命令来查看路径。

traceroute -w 1 www.cs.brown.edu

数据包首先跳转到我的无线路由器(IP: 192.168.0.1)。从下一个跳点开始,数据包进入我的互联网服务提供商(ISP)的网络。之后,数据包会经过多个位于旧金山、圣何塞等地的路由器。当路径接*目的地时,我们看到了位于波士顿附*的路由器。

在跳转13之后,我们看到三个星号(*)。这表示有一个路由器没有回复traceroute的探测包(可能是被配置为不响应)。在跳转20处,我们看到了一个属于布朗大学计算机科学部门的路由器。之后的路径就被隐藏了,因为布朗的内部网络不想对外部可见。

让我们试试追踪到麻省理工学院(MIT)实验室的路径:traceroute -w 1 www.csail.mit.edu

我们可以看到,直到跳转15,数据包都走与去布朗大学相似的路径到波士顿。之后,通往MIT的路径继续在互联网骨干网中传输。最终,从我的计算机发送的数据包在约22跳后到达其Web服务器。观察时间值,往返时间低于90毫秒,非常快。


总结 📝

本节课中,我们一起学习了一个数据包的完整生命旅程。

我们从应用层的一个Web请求开始,看到了传输层如何通过TCP三次握手建立可靠连接,以及网络层如何利用IP地址和路由器的转发表,让数据包穿越互联网(可能多达20跳)到达目的地。

我们所呈现的一切都是日常网络互动的基础。通过Wireshark和Traceroute这样的简单工具,可以清晰地看到网络原理在实际中的应用,这正是学习网络课程的魅力所在。

计算机网络课程 P50:延迟保证示例分析 📊

在本节课中,我们将通过一个具体的工作示例,学习如何分析和计算网络中的延迟保证。我们将分解总延迟的各个组成部分,并计算出在特定约束下,路由器所需的队列大小。


网络场景概述 🌐

上一节我们介绍了延迟的基本概念,本节中我们来看看一个具体的计算示例。

两个端主机被三个路由器分隔开,它们之间通过四条链路连接。以下是该网络场景的具体参数:

  • 每条链路的长度为 250公里
  • 每条链路的传输速度为 100 Mbps
  • 端主机之间相互发送的流量,其数据包长度为 1500字节
  • 流量速率为 15 Mbps
  • 端主机要求端到端的总延迟不得超过 10毫秒
  • 每个路由器以 15 Mbps 的速率处理(服务)流量。
  • 信号传播速度为 2亿米/秒
  • 总队列延迟在三个路由器中均匀分配。

延迟分解与计算 ⚙️

网络中的总延迟由固定延迟和队列延迟组成。固定延迟包括数据包化延迟和传播延迟,这两者与网络负载无关。接下来,我们将分别计算它们。

计算固定延迟

固定延迟是数据包化延迟与传播延迟的总和。

1. 计算数据包化延迟

数据包化延迟是指将一个完整的数据包推送到链路上所需的时间。其计算公式为:

数据包化延迟 = 数据包大小 / 链路带宽

对于单条链路:

  • 数据包大小 = 1500 字节 × 8 位/字节 = 12,000 位
  • 链路带宽 = 100 Mbps = 100 × 10^6 bps

因此,单个链路的传输延迟为:
12,000 bits / 100,000,000 bps = 0.00012 秒 = 0.12 毫秒

由于数据包需要依次经过全部4条链路,总的数据包化延迟为:
0.12 毫秒 × 4 = 0.48 毫秒

2. 计算传播延迟

传播延迟是指一个比特在物理链路上传播所需的时间。其计算公式为:

传播延迟 = 链路长度 / 传播速度

对于单条250公里的链路:
250 km × 1000 m/km / 200,000,000 m/s = 0.00125 秒 = 1.25 毫秒

数据需要经过全部4条链路,因此总的传播延迟为:
1.25 毫秒 × 4 = 5 毫秒

3. 总固定延迟

现在,我们可以得出总的固定延迟:
总固定延迟 = 数据包化延迟 + 传播延迟 = 0.48 毫秒 + 5 毫秒 = 5.48 毫秒

计算队列延迟

队列延迟是数据包在路由器缓冲区中等待被转发的时间。根据题目,总延迟不能超过10毫秒。

因此,允许的最大队列延迟为:
最大队列延迟 = 总延迟上限 - 总固定延迟 = 10 毫秒 - 5.48 毫秒 = 4.52 毫秒

题目假设队列延迟在三个路由器中均匀分配。所以,每个路由器允许的最大队列延迟为:
每个路由器的队列延迟 = 4.52 毫秒 / 3 ≈ 1.507 毫秒

计算路由器所需缓冲区大小 💾

在上一节我们计算出了每个路由器允许的队列延迟,本节中我们来看看如何根据这个延迟和流量速率,计算出路由器需要的最小缓冲区大小。

路由器需要存储足够的数据,以应对持续1.507毫秒的流量突发,同时其服务速率为15 Mbps。

所需缓冲区大小的计算公式为:
缓冲区大小 = 队列延迟 × 服务速率

代入数值:
缓冲区大小 = 1.507 × 10^{-3} 秒 × 15 × 10^6 bps

计算过程:
1.507 × 10^{-3} × 15 × 10^6 = 1.507 × 15 × 10^3 = 22.605 × 10^3 = 22,605 位

将位数转换为字节:
22,605 位 / 8 位/字节 ≈ 2,825.6 字节

在实际网络设备中,缓冲区通常以数据包为单位进行分配。一个数据包是1500字节,因此,为了容纳约2826字节的数据,路由器至少需要准备 2个数据包 的缓冲区空间(即3000字节)。


课程总结 📝

本节课中,我们一起学习了如何对一个具体的网络延迟保证问题进行分析和计算。我们首先将端到端总延迟分解为数据包化延迟传播延迟队列延迟。然后,我们逐步计算了固定延迟部分,并根据总延迟约束推导出允许的队列延迟。最后,我们利用队列延迟和服务速率,计算出了路由器所需的最小缓冲区大小。

通过这个例子,你可以掌握分析网络性能指标的基本方法,这对于理解服务质量(QoS)和网络设计至关重要。

计算机网络课程 P51:分组交换技术回顾 📦

在本节课中,我们将一起回顾分组交换技术的核心概念。分组交换是现代网络(包括互联网)的基础,理解其工作原理对于掌握网络动态至关重要。我们将从分组交换的基本原理开始,逐步深入到数据包延迟的构成、队列模型以及网络如何提供服务质量保证。


概述:为什么是分组交换? 🤔

我们从探讨现代网络(包括互联网)为何基于分组交换技术开始。分组交换在理论上简单,因为每个数据包都是一个包含数据的独立单位。它携带到达其目的地所需的所有信息。

分组交换在效率上高效,因为它能保持链路的忙碌状态。每当有数据传输需求时,网络就会工作,而不是为特定用户或应用程序保留专用容量。此外,分组交换有助于网络快速从故障中恢复。其简单的转发范式——每个路由器中不维护每个流的状态——使得在链路或路由器故障后能更容易地快速重新路由数据。


分组交换的动态特性与数学基础 📊

分组交换的动态特性决定了互联网的许多定时和执行特性。因此,对数据包动态有深入的理解非常重要。主要的数学思想并不复杂,现在掌握它们有助于建立强大的直觉。

你现在已经知道,为什么在两个相同的源主机和目的主机之间传输的两个数据包可能会遇到不同的延迟。尽管它们在每个链路上传输的时间相同,但这些数据包可能走不同的路径,并在路由器中经历不同的队列延迟


数据包延迟的三大组成部分 ⏱️

在深入探讨的过程中,理解数据包延迟的三个主要组成部分至关重要:分组化延迟传播延迟队列延迟,并且需要理解导致这些延迟的物理过程。

你应该养成画草图的习惯,并使用简单的确定性队列模型。这是一个简单的几何构造,能让你可视化正在发生的事情。它告诉我们路由器为什么需要缓冲区,并让我们思考缓冲区应该设置多大。它还告诉我们,流媒体应用需要播放缓冲区,以便为用户提供*滑的聆听或观看体验。当我们研究流量控制时,也会使用相同的方法。


超越简单的先到先服务 🔄

最后,我们使用简单的确定性模型来学习网络如何超越简单的“先到先服务”数据包交付。分组交换网络可以保证每个流接收的速率,甚至限制数据包从网络一端到另一端的延迟。这需要一些仔细的思考。

不要害怕这些概念一开始难以掌握。在第一部分有一些困难的概念,但它们很重要。如果你能理解分组交换网络如何提供速率和延迟保证,那么你就对分组交换的工作有了深入的理解。


本单元核心知识点总结 📚

你在这个单元中学到了很多。以下是核心知识点的总结:

1. 数据包延迟的构成

一个数据包从源主机到目的主机的旅行时间由三个组件决定:

  • 分组化延迟:在每个链路上传输数据包所需的时间。公式为:分组化延迟 = 数据包大小(比特) / 链路带宽(比特/秒)
  • 传播延迟:比特在物理介质(如电缆或空气)中传播到链路另一端所需的时间。公式为:传播延迟 = 距离 / 传播速度
  • 队列延迟:数据包在路由器缓冲区中等待转发的时间。这是延迟的可变部分,取决于网络当前的繁忙程度。

确保你明白传播延迟分组化延迟之间的差异,因为这是导致混淆的常见原因。

2. 播放缓冲区的作用

实时流媒体应用(如Skype、YouTube和Netflix)需要向我们的耳朵和眼睛持续提供实时语音和视频,尽管网络在不可预测的时间交付数据包。所有流媒体应用都使用播放缓冲区来*滑数据包延迟的各种变化,从而可以向用户连续播放视频和音频,而不必频繁暂停等待新数据。你学会了如何设计一个播放缓冲区,也理解了互联网无法完全避免暂停的原因(例如,当数据包经历较大延迟导致播放缓冲区耗尽时)。

3. 确定性队列模型

路由器中的排队是一个复杂的主题。我们希望你能够对队列的演变有一些直觉。确定性队列模型是对队列中数据包的几何表示,它让我们可以可视化队列随时间的演变。使用这个模型来帮助你建立关于数学如何工作的直觉是一个很好的习惯。

4. 速率与延迟保证

确定性队列模型帮助我们理解速率保证。例如,网络服务提供商可以通过在路由器中为特定流量(如来自斯坦福大学的所有数据包)设置专用队列并分配特定带宽(如10 Gbps),来保证其最小服务速率。这个想法可以扩展以提供延迟保证。通过控制队列的服务速度和限制队列的长度,我们可以限制数据包在队列中的最大延迟。

5. 数据包交换与转发

正如你所看到的,以太网交换机和互联网路由器的工作方式非常相似。当一个数据包到达时,它会在转发表中查找目的地地址。如果找到匹配项,它就将数据包转发到相应的出站链路,并在出站链路忙碌时将其存储在缓冲区中。互联网路由器和以太网交换机在使用的地址类型(如IP地址 vs MAC地址)以及转发表的组织方式上有所不同,并且互联网路由器会减少TTL字段以防止路由循环。但从高层次来看,数据包交换机大致以相同的方式工作。


学习成果与应用 🎯

你在这个单元中学到的东西将在许多方面帮助你:

  • 你可以根据网络描述(链路速度、长度、数据包大小)计算数据包从源到目的地的固定延迟部分。
  • 你可以通过绘制队列图来可视化可变的队列延迟,这是网络中可变端到端延迟最常见的原因。
  • 你可以解释数据包交换机(如以太网交换机或互联网路由器)的工作原理。
  • 你可以为实时应用设计一个播放缓冲区。
  • 你可以解释一个通过数据包交换机的数据流如何能够以最小保证速率进行交付。


本节课中,我们一起回顾了分组交换技术的核心原理、数据包延迟的构成、队列模型以及网络服务质量的基本概念。掌握这些知识,是理解更复杂网络协议和现象的重要基石。

课程 P52:拥塞控制 🚦

在本节课中,我们将学习计算机网络中的拥塞控制。我们将了解它的基本概念、目标,并深入探讨TCP协议中使用的具体拥塞控制算法。


概述

你已经知道有一种叫做流量控制的东西。流量控制是我们试图防止发送者压倒接收者的时候,由接收者告诉发送者减速。

拥塞控制本质上是将这个概念扩展到整个网络。你可以想象,如果发送者向网络发送太多的包,他们将会压倒网络。路由器的缓冲区将填满,链接将溢出,我们将开始丢弃数据包。显然,这不是一件很好的事情。

拥塞控制是关于防止发送者过度淹没网络的。因此,我们自然地提出了一个问题:我们如何做到这一点?


拥塞控制的目标

上一节我们介绍了拥塞控制的基本概念,本节中我们来看看我们对拥塞控制机制有哪些期望。

以下是拥塞控制机制需要满足的主要目标:

  1. 防止过度淹没:它需要防止网络因数据包过多而发生过载。
  2. 公*性:我们通常希望均匀地分散“痛苦”。我们希望确保所有被控制的流量都以公*和相等的方式被控制。

实现位置:端到端原则

一个大问题是:我们想要控制拥堵,但应该在哪里做?应该在网络边缘做,还是在网络内部做?

如果我们遵循端到端原则,将复杂的功能正确地导向终点,你会说我们希望网络仅转发数据包,我们希望智能位于边缘。这在实践中,通常是今天所采用的方法。

因此,在这个单元中,我们将讨论TCP,并讨论TCP如何控制拥塞。事实证明,这是它最重要的特性之一。


TCP的拥塞控制

一个TCP发送者可以控制它向网络放入的包数,以确保它不会造成拥堵。这就是端到端的方法,它使网络的内部保持简单。结果你会发现,只在边缘做拥塞控制,也可以做得非常好。

TCP拥塞控制选择使用一种特定的算法,叫做累加增加,乘法减少,或 AIMD

这个算法具有许多非常有趣的特性。当你实际查看它在拥有数百万个竞争流量的庞大而复杂的网络中的行为时,它具有非常美好的稳定特性,允许它很好地控制拥堵。而且,它以一种公*的方式运作。

这个想法被许多人认为是网络领域的一颗明珠,是最重要的智力想法之一。它存在于TCP中,已经存在了大约二十五年。


本单元学习内容

在本单元中,你将学习:

  • 关于拥塞控制的概念。
  • 我们期望从拥塞控制算法中获取的性质。
  • TCP中使用的具体拥塞控制机制,即菲尔刚才提到的AIMD
  • 详细解释它如何工作,它在实践中是如何实现的。
  • 它在不同场景中如何工作:当你只有一个流量时发生什么,或者当你有许多流量时发生什么。

你将学到的不仅仅是今天的TCP,它将给你很多关于TCP的深入理解。


总结

本节课中,我们一起学习了拥塞控制的核心思想。我们了解到,它是为了防止发送者过度淹没整个网络,而不仅仅是接收端。我们探讨了其防止过载保证公*性的目标,并引入了端到端原则作为其实践基础。最后,我们预告了TCP中使用的AIMD算法将是后续深入学习的重点。掌握这些,是理解现代网络可靠传输的关键。

课程P53:拥塞控制基础 🚦

在本节课中,我们将要学习网络中的一个核心概念——拥塞控制。我们将探讨什么是网络拥塞,它为何会发生,以及控制拥塞的基本原理和目标。理解这些基础知识,是后续学习具体拥塞控制算法(如TCP中的算法)的关键。

什么是网络拥塞?🤔

上一节我们介绍了课程概述,本节中我们来看看拥塞的具体含义。网络拥塞是指网络中的数据流量超过了网络设备(如路由器)的处理能力,导致数据包延迟增加、丢失,甚至网络性能急剧下降的现象。拥塞可能发生在不同的时间尺度上。

以下是三种常见的时间尺度示例:

  1. 极短时间尺度(包碰撞):当两个或多个数据包几乎同时到达路由器并竞争同一个输出链路时,会发生瞬时排队。例如,代码可以模拟为两个数据包到达事件的时间差极小。

    packet1.arrival_time = t
    packet2.arrival_time = t + ε // ε是一个非常小的值
    

    其中一个数据包被立即发送,另一个则进入缓冲区排队,造成短暂的队列堆积。

  2. 中等时间尺度(流级别):在往返时间(RTT)或数个RTT的时间尺度上,例如一个TCP连接在下载文件。如果多个数据流(flow)的发送速率之和超过了某条链路的容量,缓冲区就会持续累积并最终溢出。假设链路容量为 C,两个流的发送速率分别为 r1r2,当 r1 + r2 > C 时,就会发生拥塞。

  1. 长时间尺度(人类活动周期):例如在高峰时段,大量用户同时访问某个热门网站(如新闻站点),导致连接到该服务器的链路过载。

在拥塞控制中,我们主要关注和试图解决的是第二种时间尺度——流级别的拥塞,因为我们有机会通过反馈机制调整发送端的速率。

拥塞的影响与反馈效应 🔄

让我们通过一个具体例子深入理解拥塞的影响。假设源A和源B都希望以12 Mbps的速率向目的地X发送数据。然而,路由器R到X的链路容量只有12 Mbps。

  • 设A的发送速率为 r_A = 12 Mbps
  • 设B的发送速率为 r_B = 12 Mbps
  • 链路容量 C = 12 Mbps

显然,总到达速率 r_A + r_B = 24 Mbps 大于离开速率 C = 12 Mbps。根据确定性排队模型,队列长度 q(t) 将随时间线性增长:q(t) = (r_A + r_B - C) * t

最终,路由器的缓冲区会溢出,导致数据包被丢弃。这些被丢弃的包通常需要重传,而重传又会向网络中注入更多的流量,从而进一步加剧拥塞,形成一个使情况恶化的正反馈循环。因此,拥塞控制的核心目标之一就是避免网络进入这种状态。

公*分配问题 ⚖️

当多个流共享一个瓶颈资源时,如何公*地分配带宽成为一个关键问题。假设链路容量为 C,有两个流竞争,它们期望的速率分别为 r1r2

一种直观的公*分配方式是“最大最小公*”(Max-Min Fairness)。其定义是:一种速率分配是最大最小公*的,当且仅当无法在不降低一个更低速率的流的速率的情况下,去提高任何一个流的速率。

在单个瓶颈链路的简单情况下,最大最小公*意味着:

  • 如果每个流的需求都超过其公*份额(即 r1 > C/2r2 > C/2),则每个流获得 C/2
  • 如果某个流的需求小于其公*份额(例如 r1 < C/2),则它获得其所需速率 r1,剩余的带宽 (C - r1) 再在剩余流之间公*分配。

以下是一个计算示例:

链路容量 C = 1 Mbps。
流A需求:0.5 Mbps,流B需求:0.8 Mbps,流C需求:0.2 Mbps。

  1. 初始公*份额为 C/3 ≈ 0.33 Mbps。
  2. 流C需求0.2 Mbps < 0.33 Mbps,故满足其需求,分配0.2 Mbps。剩余带宽 0.8 Mbps。
  3. 剩余带宽在A和B间分配,公*份额变为 0.8 / 2 = 0.4 Mbps。
  4. 流A需求0.5 Mbps > 0.4 Mbps,故分配0.4 Mbps。
  5. 流B需求0.8 Mbps > 0.4 Mbps,故分配0.4 Mbps。
    最终分配:(A: 0.4, B: 0.4, C: 0.2),总和为1 Mbps,符合最大最小公*原则。

拥塞的必然性与设计目标 🎯

需要认识到,在分组交换网络中,一定程度的拥塞是不可避免甚至有益的。它意味着网络资源(链路、缓冲区)得到了充分利用。如果缓冲区总是空的,虽然延迟低,但链路利用率也低,是一种资源浪费。拥塞控制的目标不是彻底消除拥塞,而是将其控制在一个合理的水*,在高吞吐量低延迟之间取得*衡。

基于以上讨论,一个理想的拥塞控制机制应追求以下目标:

以下是拥塞控制机制的四个核心目标:

  1. 高吞吐量(High Throughput):有效利用网络带宽,保持链路繁忙,使数据快速传输完毕。
  2. 公*性(Fairness):通常依据最大最小公*准则,确保竞争同一瓶颈资源的各流量能获得公*的带宽份额,同时保护小流量。
  3. 快速收敛与响应(Responsiveness):能快速感知网络状态变化(如新流量加入或旧流量离开),并相应调整发送速率,以充分利用可用带宽或缓解拥塞。
  4. 分布式部署(Distributed):算法应能分布式运行,不依赖于中央控制器,以保证可扩展性和鲁棒性。

总结 📝

本节课中我们一起学习了拥塞控制的基础知识。我们首先了解了网络拥塞在不同时间尺度上的表现形式及其负面影响,特别是由丢包重传引发的反馈效应。接着,我们探讨了在共享瓶颈资源时的公*分配问题,并介绍了“最大最小公*”这一重要准则。最后,我们明确了设计拥塞控制算法时所追求的四大目标:高吞吐量、公*性、快速响应和分布式部署。这些概念和目标是理解后续各种具体拥塞控制算法(如TCP Reno、CUBIC等)的基石。

课程 P54:TCP 拥塞控制基础 2 🚦

在本节课中,我们将学习网络拥塞控制的基本方法,探讨控制机制应该部署在网络中还是终端主机上,并详细介绍 TCP 所采用的“加性增、乘性减”核心算法。


网络中的拥塞控制

上一节我们介绍了拥塞的类型和后果。本节中,我们来看看控制拥塞的基本方法。

首先,我们需要考虑拥塞控制应该在网络中进行(即在路由器中提供特定支持),还是在终端主机中完成。

你可能会好奇,为什么不能简单地使用公*队列调度器来分配链路带宽。这种方法确实可以为每个竞争流提供公*的份额,并保持链路忙碌。然而,它存在一个关键问题:它无法主动告知发送源应以何种速率发送数据。如果所有源都以最大速率发送,数据包最终会在缓冲区溢出时被丢弃,从而浪费了上游带宽。

因此,我们需要一种方式向发送源发送信号,指示其应采用的发送速率或网络中允许的未完成数据包数量。

基于网络的拥塞控制

在基于网络的拥塞控制中,路由器会提供明确的反馈来指示网络中的拥塞。

以下是其工作原理的关键点:

  • 信号内容:信号可以是数据包丢弃指示、缓冲区占用率、超过某个拥塞阈值,或是出站链路剩余容量的指示。
  • 信号形式:通常使用一到两个比特位来向源发送信号,以节省开销。
  • 信号传递:常见做法是将信号“搭载”在已经传输的数据包上(例如在确认包中返回),而不是创建新的数据包。一种具体技术称为显式拥塞通知

基于网络的方法优点明显:信号直接控制源的行为,对变化反应快,并且是分布式的。然而,它需要网络设备(路由器)的支持。


终端主机的拥塞控制

接下来,我们探讨是否可以在没有任何网络支持的情况下,仅在终端主机上实现拥塞控制。

这种方法的核心思想是:发送主机通过观察网络行为(如数据包丢失、延迟增加等),自行推断拥塞状况并调整发送行为。TCP 协议正是这样做的,因为 IP 协议默认不提供拥塞指示。

TCP 在终端主机上实现拥塞控制,它会对主机可观测到的事件做出反应,特别是数据包丢失。TCP 利用其滑动窗口机制来控制网络中未完成数据包的数量。

TCP 滑动窗口回顾

在深入拥塞控制之前,让我们快速回顾一下 TCP 滑动窗口的工作原理。

滑动窗口定义了字节流中三个关键部分:

  1. 已发送且已被确认的数据。
  2. 已发送但尚未确认的数据(即“未完成”数据)。
  3. 允许发送但尚未发送的数据(在窗口内)。

窗口大小决定了允许发送但未被确认的最大数据量。如果往返时间等于用窗口数据填满网络管道所需的时间,那么数据可以连续发送,从而充分利用网络。


TCP 拥塞窗口与 AIMD 算法

现在,我们来看看 TCP 如何具体利用窗口机制进行拥塞控制。

TCP 发送方会维护两个窗口值:

  • 接收窗口:由接收方通告,防止发送方压倒接收方。
  • 拥塞窗口:由发送方根据网络拥塞状况自行计算得出,通常缩写为 cwnd

实际发送窗口的大小是上述两者中的较小值。当网络拥塞时,通常由 cwnd 主导。

核心算法:加性增、乘性减

那么,发送方如何决定 cwnd 的值呢?TCP 使用一种被称为 AIMD 的经典算法。

以下是 AIMD 的工作原理:

  • 加性增:当传输顺利,没有数据包丢失时,发送方每成功接收并确认一个完整窗口的数据,就将 cwnd 增加 1 个数据包的大小。这是一种缓慢、线性的增长。
    • 公式表示:cwnd = cwnd + 1 (每经过一个 RTT)
  • 乘性减:当检测到数据包丢失(视为拥塞信号)时,发送方将 cwnd 减少到当前值的一半。这是一种快速、剧烈的下降。
    • 公式表示:cwnd = cwnd / 2

可视化:TCP 锯齿

如果将 cwnd 随时间的变化绘制出来,我们会看到一个典型的“锯齿”形状:

  1. cwnd 在成功传输期间线性增长(加性增)。
  2. 当发生丢包时,cwnd 突然减半(乘性减)。
  3. 然后 cwnd 再次开始线性增长,如此循环。

这种模式被称为 TCP 锯齿AIMD 锯齿。它形象地展示了 TCP 如何探索并适应网络可用带宽:缓慢增加以利用空闲带宽,一旦拥塞则快速后退。


总结

本节课中,我们一起学习了:

  1. 控制位置的选择:拥塞控制可分为基于网络(路由器提供信号)和基于终端主机两种方式。
  2. TCP 的选择:由于 IP 协议缺乏内置支持,TCP 在终端主机上实现拥塞控制,通过观察数据包丢失等事件来推断拥塞。
  3. 核心机制:TCP 通过动态调整拥塞窗口 的大小来控制注入网络的数据量。
  4. AIMD 算法:这是 TCP 拥塞控制的核心算法,包括加性增(无拥塞时缓慢增加窗口)和乘性减(检测到拥塞时快速减半窗口),其运行结果形成了典型的“TCP 锯齿”带宽利用模式。

课程 P55:单条 AIMD 流的动态分析 🧮

在本节课中,我们将学习 TCP 拥塞控制的核心机制——加性增、乘性减(AIMD)算法。我们将通过分析网络中单条 AIMD 流的动态行为,来理解 TCP 如何在没有网络明确支持的情况下,仅通过端主机调节滑动窗口大小来应对拥塞。

上一节我们介绍了 AIMD 的基本概念,本节中我们来看看它在单条数据流中的具体工作过程。

AIMD 算法回顾

AIMD 算法用于调节 TCP 滑动窗口的大小(w),从而控制网络中“在途字节”的数量。其核心规则如下:

  • 加性增:每当成功收到一个完整窗口的数据包确认时,窗口大小增加一个单位。
    • 公式:w = w + 1
  • 乘性减:每当检测到数据包丢失(视为拥塞信号)时,窗口大小减半。
    • 公式:w = w / 2

这种方法的目标是:在无拥塞时谨慎增加发送量以探测可用带宽;在出现拥塞时迅速减少发送量以缓解网络压力。

单流 AIMD 动态模拟分析

为了深入理解,我们观察一个 AIMD 流通过单个瓶颈链路的动画模拟。网络结构如下:源主机和目的主机之间有一个路由器,其出口链路(右侧)是瓶颈,速度慢于入口链路(左侧)。

以下是模拟中的关键组件和行为:

  • 拥塞窗口 (w):图中红线,代表源端允许的未确认数据包数量。它随时间变化。
  • 路由器缓冲区:位于瓶颈链路前,用于暂存无法立即转发的数据包。
  • 数据包流:蓝色数据包从源流向目的地。
  • 确认包流:红色确认包从目的地返回源端,用于触发后续数据包的发送(自时钟驱动)。

当窗口 w 较小时,数据包填满传输链路,缓冲区为空。随着 w 被“加性增”规则调大,由于链路已满,额外的数据包只能进入缓冲区,导致缓冲区占用率上升。最终,缓冲区会满并发生丢包。触发“乘性减”规则,w 减半,源端发送速率骤降,缓冲区开始排空。之后,w 再次开始缓慢增长,循环往复。

这个过程中有一个关键现象:尽管拥塞窗口 w 呈锯齿状振荡,但瓶颈链路的利用率始终保持在 100%。数据包的发送速率基本保持恒定。

核心动态与观察

通过分析模拟,我们可以得出关于单条 AIMD 流的几个重要观察:

  1. 窗口与延迟同步:拥塞窗口 w 的增加会导致缓冲区排队的数据包增多,从而增加数据包的往返时间(RTT)。因此,w 和 RTT 同步增长和减少。
  2. 发送速率恒定:发送速率可以定义为 w / RTT。由于 w 和 RTT 同步变化,它们的比值 w / RTT 在实际中*似为一个常数。这解释了为何瓶颈链路能始终保持繁忙。
  3. 缓冲区大小的重要性:为了使 AIMD 流高效工作(即保持 100% 链路利用率),路由器需要足够大的缓冲区。理想的最小缓冲区大小应为 RTT × C,其中 C 是瓶颈链路的容量(带宽)。这个大小的缓冲区可以吸收窗口 w 减半期间未被链路消耗的数据包,防止缓冲区变空导致链路闲置。

总结

本节课中我们一起学习了 AIMD 算法在单条网络流中的动态行为。我们了解到:

  • AIMD 通过锯齿状的窗口振荡,稳定地探索网络管道从端到端能容纳的数据量。
  • 这种振荡是 TCP 在稳定状态下的正常行为,它使得发送速率保持恒定,并充分利用了瓶颈带宽。
  • 为了保证效率,网络中的瓶颈路由器需要配置大小约为 RTT × C 的缓冲区。

本质上,对于单条流,AIMD 并未直接调节发送速率,而是在调节网络中“在途数据”的数量,并间接实现了链路的高效利用。在下一个视频中,我们将看到当网络中存在多条竞争流时,情况会变得更加复杂和有趣。

课程 P56:单流 AIMD 拥塞控制工作示例 📊

在本节课中,我们将通过一个具体的工作示例,详细分析单流 AIMD(加性增乘性减)拥塞控制机制的行为。我们将计算关键参数,如拥塞窗口的最小值与最大值、缓冲区大小以及恢复时间,以深入理解 AIMD 如何在实际网络中运作。


概述与场景设定 🌐

首先,我们来设定示例场景。Alice 正在从一台远程服务器流式传输高清视频,其瓶颈链路带宽为 10 Mbps。所有数据包的长度固定为 250 字节。她测量到服务器的最小往返时间(RTT)为 5 毫秒。我们假设 AIMD 窗口已达到稳定状态,并且路由器缓冲区大小经过完美调整,既不会溢出也不会变空。

上一节我们介绍了基本场景,本节中我们来看看如何根据这些信息计算 AIMD 窗口的边界值。


第一部分:计算 AIMD 窗口最小值 🔽

当网络路径中的缓冲区为空时,我们观察到最小的 RTT 为 5 毫秒。此时,瓶颈链路(10 Mbps)是满的,这意味着有数据包正在“管道中飞行”。

计算管道中的数据量(即带宽延迟积):
公式:数据量 (比特) = 带宽 (bps) × 延迟 (秒)

代入数值:
数据量 = 10 × 10^6 bps × 5 × 10^-3 秒 = 50,000 比特

这 50,000 比特代表了 AIMD “锯齿波”振荡时的最低点,即窗口最小值。将其转换为字节(1 字节 = 8 比特):
50,000 比特 ÷ 8 = 6,250 字节

因此,AIMD 窗口的最小值为 6,250 字节。


第二部分:计算 AIMD 窗口最大值 🔼

当路由器缓冲区被填满时,总延迟(RTT)会从最小值 5 毫秒增加到 10 毫秒。此时,网络中总的数据量包括两部分:填满管道的数据和填满缓冲区的数据。

总数据量计算:
总数据量 = 带宽 × 最大RTT = 10 × 10^6 bps × 10 × 10^-3 秒 = 100,000 比特

这 100,000 比特代表了 AIMD “锯齿波”振荡时的最高点,即窗口最大值。转换为字节:
100,000 比特 ÷ 8 = 12,500 字节

因此,AIMD 窗口的最大值为 12,500 字节。


第三部分:计算路由器缓冲区大小 🗃️

从第二部分的分析可知,当 RTT 从 5ms 增至 10ms 时,增加的 5ms 延迟正是由缓冲区中的数据造成的。

因此,缓冲区容量等于带宽与额外延迟的乘积:
缓冲区容量 = 带宽 × (最大RTT - 最小RTT) = 10 × 10^6 bps × 5 × 10^-3 秒 = 50,000 比特

转换为字节:
50,000 比特 ÷ 8 = 6,250 字节

所以,路由器的包缓冲区大小为 6,250 字节。


第四部分:计算从丢包恢复至最大窗口的时间 ⏱️

现在,我们计算在初始场景(RTT=5ms)下,发生一次丢包后,拥塞窗口从减半后的值重新增长到最大值所需的时间。

已知每个数据包为 250 字节,即 2,000 比特。在 AIMD 的“加性增”阶段,每个 RTT 窗口增加一个数据包的大小,即 2,000 比特。

需要增加的数据量是缓冲区的大小,即 50,000 比特
所需 RTT 轮次计算:
所需轮次 = 需增加数据量 / 每轮次增加量 = 50,000 比特 / 2,000 比特每RTT = 25 个 RTT

在稳定状态下,*均 RTT 介于最小 RTT(5ms)和最大 RTT(10ms)之间,我们取*均值 7.5 毫秒
总恢复时间计算:
总时间 = RTT轮次 × *均RTT = 25 × 7.5 毫秒 = 187.5 毫秒

因此,从丢包恢复至最大窗口需要 187.5 毫秒。


第五部分:高延迟场景下的缓冲区需求 ✈️

接下来,我们考虑一个变化:Alice 改为连接位于澳大利亚的服务器,最小 RTT 变为 250 毫秒,但瓶颈带宽仍为 10 Mbps。我们需要计算此时所需的缓冲区大小。

为确保缓冲区不会在 AIMD 周期内变空,其容量至少需要容纳最小 RTT 对应的带宽延迟积:
缓冲区容量 = 带宽 × 最小RTT = 10 × 10^6 bps × 250 × 10^-3 秒 = 2,500,000 比特

在计算机存储中,我们通常使用 2 的幂次单位。进行单位换算:
2,500,000 比特 ÷ 8 = 312,500 字节 ≈ 305 千字节 (KiB)

2,500,000 比特 ≈ 2.38 兆比特 (Mib)

因此,在高延迟场景下,路由器缓冲区至少需要约 305 KB。


第六部分:高延迟场景下的恢复时间问题 🐌

最后,我们计算在高延迟(澳大利亚服务器)场景下,发生丢包后的恢复时间。

需要填充的缓冲区容量为 2.5 × 10^6 比特
每个 RTT 窗口仍增加一个数据包的大小:2,000 比特
所需 RTT 轮次计算:
所需轮次 = 2.5 × 10^6 比特 / 2,000 比特每RTT = 1,250 个 RTT

此时,*均 RTT 介于 250ms 和 500ms(2倍最小RTT)之间,取*均值 375 毫秒
总恢复时间计算:
总时间 = 1,250 × 0.375 秒 = 468.75 秒 ≈ 7.8 分钟

这个结果令人惊讶:在高延迟网络中,一次简单的数据包丢失可能导致 AIMD 流需要* 8 分钟才能完全恢复速度。 这揭示了经典 AIMD 算法的一个重大缺陷,即在长肥网络(LFN)中效率低下,从而促使了 TCP 更快恢复算法(如 Reno、Cubic)的研究与发展。


总结 📝

本节课中我们一起学习了单流 AIMD 拥塞控制的工作示例。通过逐步计算,我们得出了以下核心结论:

  • AIMD 窗口在 带宽延迟积(BDP)BDP + 缓冲区容量 之间振荡。
  • 路由器缓冲区的最佳大小约等于一个最小 RTT 的带宽延迟积。
  • 恢复时间 对延迟非常敏感。在长延迟网络中,经典 AIMD 从丢包中恢复的速度极慢,这成为其在实际应用中的主要瓶颈,并推动了更先进拥塞控制算法的出现。

这个示例清晰地展示了理论模型与实际网络性能之间的关系。

课程 P57:多流情况下的AIMD算法 🚦

在本节课中,我们将要学习AIMD(加性增乘性减)算法在网络中存在多个并发数据流时的工作原理。我们将重点关注其动态特性、吞吐量计算以及与单流情况的区别。


概述

上一节我们介绍了在单一主导流量下,AIMD算法如何通过控制窗口大小来管理网络拥塞。本节中我们来看看当网络中存在大量并发数据流时,AIMD的行为会发生怎样的变化。

AIMD是 Additive Increase Multiplicative Decrease 的缩写。它通过调整窗口大小来控制网络中“在途数据包”(即已发送但未确认的数据包)的数量,从而间接管理拥塞。


单流与多流的核心区别

在单一流量场景中,AIMD的“锯齿”波形与往返时间(RTT)同步变化。然而,在互联网的真实环境中,路由器通常需要同时处理成千上万个数据流。

当网络中存在大量流量时,路由器缓冲区中会混杂着来自不同流的众多数据包。此时,任何单一流的数据包通常只占缓冲区总容量的一小部分。

由于缓冲区几乎总是被高度占用,数据包经历的排队延迟相对稳定。因此,一个非常合理的假设是:在多流情况下,往返时间RTT基本保持恒定

这与单流情况形成鲜明对比。在单流情况下,窗口增大时RTT也会随之增加,导致吞吐量曲线的顶部边缘弯曲。而在多流情况下,RTT恒定,使得AIMD的吞吐量曲线呈现标准的直角三角形锯齿状。


多流下的吞吐量分析

一个流的吞吐量,即每秒发送的字节或数据包数量,可以通过其窗口大小和RTT计算。在每个RTT周期内,发送的数据量等于当前的窗口大小。

因此,流的吞吐量 T 与其窗口大小 W 成正比,与RTT R 成反比,关系可以表示为:

T ∝ W / R

由于我们假设RTT R 是常数,因此*均吞吐量就与*均窗口大小成正比


吞吐量与丢包率的关系

接下来,我们通过几何方法推导吞吐量 T、RTT R 和丢包概率 p 之间的关系。

以下是分析步骤:

  1. 观察锯齿图形:在一个完整的AIMD周期(从一次丢包到下一次丢包)中,窗口大小从 W_max/2 线性增加到 W_max
  2. 计算周期内发送量:这个周期内发送的数据总量 A,等于图中直角三角形的面积。经过计算可得:
    A = (3/8) * W_max²
  3. 建立与丢包率的联系:每次发送 A 量的数据,就会发生一次丢包。因此,丢包概率 p 是发送量的倒数:
    p = 1 / A
  4. 推导吞吐量公式:吞吐量 T 是周期内发送量 A 除以周期时长。周期时长等于步数 (W_max/2) 乘以常数RTT R。结合以上关系,最终得到著名的*方根公式

T ≈ (√(3/2)) / (R * √p)


公式的启示

这个简洁的公式揭示了AIMD在多流环境下的两个关键特性:

  1. 吞吐量与RTT成反比T ∝ 1/R

    • 这意味着与更远(RTT更大)的服务器通信时,流获得的吞吐量会更低。这通常被视为AIMD的一个缺点,因为它“惩罚”了距离更远的流量。
  2. 吞吐量与丢包率的*方根成反比T ∝ 1/√p

    • 当丢包率 p 趋*于0时,吞吐量 T 理论上会趋*于无穷大。这正反映了AIMD的行为:如果没有丢包信号,发送方的窗口就会无限增长,失去“刹车”机制。这再次印证了丢包是AIMD进行拥塞控制的核心信号


总结

本节课中我们一起学习了AIMD算法在多流量网络环境下的表现。我们了解到:

  • 当网络承载许多流时,每个流独立遵循AIMD规则,通过“锯齿”过程探索合适的窗口大小。
  • 由于缓冲区被大量流共享且持续高占用,可以假设RTT基本恒定。
  • 由此推导出吞吐量公式 T ≈ k / (R * √p),它表明吞吐量对往返时间RTT丢包概率p都非常敏感。

AIMD是TCP拥塞控制算法的基石之一。在接下来的课程中,我们将看到TCP如何将AIMD与其他多种机制结合,构成一个更完善、高效的拥塞控制工具箱。

课程 P58:TCP Tahoe 拥塞控制详解 🚦

在本节课中,我们将学习 TCP Tahoe 拥塞控制机制的核心原理。我们将了解 TCP 如何通过“加性增、乘性减”算法来管理网络中的数据流,以避免网络拥塞并提升传输效率。


概述

TCP 被认为是网络领域的一项巨大成就,它作为一种可靠的传输层协议,能在各种网络环境中良好运行。本视频解释了 TCP 如何使用一个简单的有限状态机来控制网络中数据包的数量,从而实现高效的拥塞控制。


拥塞控制的基本概念

上一节我们介绍了 TCP 的重要性,本节中我们来看看拥塞控制要解决的核心问题。

流量控制旨在防止发送方过度加载接收方。但网络拥塞发生在数据包发送速率超过网络路径中瓶颈链路的处理能力时。假设数据从旧金山传输到波士顿,途中的每个路由器都有自己的队列。如果发送速率适中,数据包丢失率会很低。但如果发送速率过高,路由器队列将溢出,导致数据包被丢弃。

数据包丢失会触发重传,从而消耗额外时间并降低性能。因此,拥塞控制的目标是动态调整发送方未被确认的数据包数量,使其接*但不超过网络的支持能力。

困难在于,TCP 发送方对网络内部状态(如路由器队列长度)知之甚少。它只能从有限的信号(如数据包确认和丢失)中推断网络状况。


AIMD 算法与拥塞窗口

基本总结是,在稳定状态下,TCP 使用 AIMD 算法。它维护一个名为 拥塞窗口 的变量。拥塞窗口指定了连接在网络中允许存在的、未被确认的报文段最大数量。

当发送方收到一个确认时,意味着一个报文段已成功离开网络。因此,在每个往返时间内,TCP 可以通过增加拥塞窗口的大小来发送更多数据。具体来说,它采用“加性增”策略。

核心公式:

  • 加性增:每个 RTT 周期,拥塞窗口增加 1个 MSS
  • 乘性减:当检测到数据包丢失时,拥塞窗口减半(或重置为1个MSS)。

到目前为止,我们解释了拥塞控制问题的出现,以及 AIMD 作为一种简单高效的解决方案。但这并非一蹴而就。


TCP 拥塞控制的历史演进

TCP 的演进是一个伟大的故事。早期互联网曾因拥塞而崩溃。在 20 世纪 80 年代中期,随着 TCP 流开始饱和链路,路由器开始丢弃数据包,而 TCP 的重传机制反应不佳,经常重传已成功到达的包,继续浪费饱和链路的容量。这导致了“拥塞崩溃”:网络极度拥堵,但应用程序的有效吞吐量却极低。

1988年,Van Jacobson 深入研究了这一问题并修复了 TCP,发表了开创性的论文。其算法构成了今天所有 TCP 实现的基础,这种 TCP 被称为 TCP Tahoe。后续的 TCP Reno 版本又进行了一些改进。现代 TCP 虽增加了复杂性,但其核心仍是 Reno。


TCP 发送数据的三个核心问题

我们可以将 TCP 的数据发送行为简化为三个问题:

  1. 何时发送新数据?
  2. 何时重传数据?
  3. 何时发送确认?

本视频将解释第一个问题。第二和第三个问题将在下一个关于 RTT 估计和自我时钟的视频中解答。


旧 TCP 的问题与 Tahoe 的改进

记住,TCP 头部有一个窗口字段,用于流量控制,确保发送方不超过接收方的处理能力。然而,如果接收方窗口远大于网络所能支持的容量,就会出问题。

早期 TCP 在完成三次握手后,会立即发送一整个流量控制窗口的数据。如果瓶颈链路只能排队几个数据包,那么后续的数据包将被大量丢弃。

下图来自确立 TCP 拥塞控制的经典论文,展示了旧 TCP 的低效行为:它立即发送大量数据段,远超网络处理能力,导致频繁丢包和超时重传,形成锯齿状的低效传输模式。

因此,TCP Tahoe 引入了三项关键改进:

  1. 拥塞窗口
  2. 更好的超时估计
  3. 自我计时

本视频重点讲解第一项改进。


拥塞窗口与两种状态

流量控制窗口防止压垮接收方,而拥塞窗口则防止压垮网络。发送方的实际发送窗口是这两个窗口的最小值。

TCP Tahoe 将拥塞控制分为两个状态:

  • 慢启动
  • 拥塞避免

在连接开始时或发生数据包超时后,TCP 进入慢启动状态。当接*网络容量时,TCP 过渡到拥塞避免状态,并遵循 AIMD 策略。


慢启动状态的工作原理

当 TCP 进入慢启动状态时,其拥塞窗口被设置为 1个 MSS。此后,每收到一个新的确认,拥塞窗口就增加 1个 MSS

代码逻辑描述:

cwnd = 1 MSS
for each new ACK received:
    cwnd += 1 MSS

这意味着拥塞窗口呈指数增长:1, 2, 4, 8, 16... 虽然名为“慢启动”,但相比旧方法(立即发送整个窗口),其增长是受控的;相比后续的“加性增”,其增长又是快速的。


拥塞避免状态的工作原理

在拥塞避免状态,TCP 增加窗口的速度要慢得多。它每个 RTT 周期才将拥塞窗口增加 1个 MSS

实现方式:假设当前拥塞窗口大小为 W 字节(即 W/MSS 个报文段)。那么,每收到一个确认,窗口的增加量是 (1 MSS) * (MSS / W)。这样,当 W/MSS 个确认全部到达后,窗口总共增加了 (W/MSS) * (MSS / W) * 1 MSS = 1 MSS

公式描述:
每个ACK带来的窗口增量 = MSS * (MSS / cwnd)

这就是 AIMD 中“加性增”的部分。


状态转换与信号

TCP 根据三种信号在两种状态间转换:

  1. 新确认:传输顺利,继续增加窗口。
  2. 三个重复确认:表明很可能有单个报文段丢失,但后续报文段已到达。
  3. 超时:表明有严重问题,可能发生了多个报文段丢失或网络中断。

以下是 TCP Tahoe 的状态转换规则:

  • 慢启动开始。
  • 当拥塞窗口超过一个称为 慢启动阈值 的值时,转入拥塞避免
  • 当发生超时三个重复确认时,TCP 返回到慢启动状态,并将 ssthresh 设置为当前拥塞窗口的一半,然后将拥塞窗口重置为 1 MSS。

下图展示了 TCP Tahoe 拥塞窗口随时间变化的典型锯齿状模式:指数增长 -> 丢包(超时或3个DupACK)-> 窗口骤降并重置 -> 再次慢启动 -> 达到阈值后进入拥塞避免。


总结

本节课中我们一起学习了 TCP Tahoe 拥塞控制机制。我们了解到:

  1. TCP 通过 拥塞窗口 来限制网络中未被确认的数据量,发送窗口是拥塞窗口和流量控制窗口的最小值。
  2. 核心算法是 AIMD:无丢包时加性增,检测到丢包时乘性减。
  3. TCP Tahoe 通过 慢启动拥塞避免 两种状态来管理窗口增长。
  4. 它使用 新确认三个重复确认超时 作为状态转换的信号。
  5. 这种机制有效解决了早期互联网的拥塞崩溃问题,是 TCP 可靠高效运行的基础。

这回答了“TCP何时发送新数据”的问题:当发送窗口允许时。发送窗口由拥塞窗口动态调节,以适应网络状况。

计算机网络课程 P59:TCP Tahoe 拥塞控制 🚦

在本节课中,我们将学习网络拥塞控制的基本概念,并深入探讨TCP协议中第一个成功解决此问题的版本——TCP Tahoe。我们将重点介绍其核心机制之一:慢启动。

概述

网络拥塞控制的核心思想是,发送数据的终端节点需要控制其发送速率,以避免过度负载网络。如果发送速率超过了网络路径中瓶颈链路所能支持的能力,就会导致大量数据包被丢弃,进而引发频繁的重传,最终使得网络性能急剧下降。TCP Tahoe通过引入拥塞窗口的概念,并采用慢启动拥塞避免两种状态来动态调整发送速率,从而有效缓解了这一问题。

拥塞控制的基本动机

上一节我们提到了拥塞控制的重要性,本节中我们来看看其产生的具体背景。

流量控制机制(如TCP头部的窗口字段)规定了接收方能接受的数据量。然而,接收方的处理能力可能远大于网络路径的实际承载能力。

例如,波士顿的接收节点可能有一个能容纳100个数据包的缓冲区,但从旧金山到波士顿的路径上可能存在一个瓶颈链路,其实际只能支持每秒传输约5个数据包。如果旧金山的发送方仅根据流量控制窗口(即接收方能力)以高速率发送数据,它将发送远超网络承载能力的包。这会导致大多数数据包被丢弃,发送方需要花费大量时间进行重传来恢复,造成网络资源浪费和性能低下。

因此,网络拥塞控制的基本思想是:终端节点应控制其数据发送速率,以避免使网络过载,这通常能提升网络的整体性能。

TCP的发展与拥塞崩溃

如果我们从更宏观的视角退一步看,真正推动拥塞控制研究的是TCP协议及其在实践中遇到的问题。

TCP协议在1974年通过握手建立。1978年,TCP和IP被分割开来。1983年1月1日,整个ARPANET切换到了TCP/IP协议栈。然而,在此之后的大约三年,互联网开始遭受“拥塞崩溃”。在拥塞崩溃中,链路虽然被数据包塞满(以线速运行),但实际有效的应用层吞吐量却为零。因为链路上传输的绝大多数数据包都是不必要的重传或确认包。

Van Jacobson在一篇标志性的论文中分析了这一问题,并提出了解决方案。他发表的这篇里程碑式论文描述了TCP Tahoe。名字“Tahoe”和后来的“Reno”来源于发布这些TCP实现的伯克利Unix版本代号。如今,几乎所有TCP实现都包含了源自TCP Tahoe和TCP Reno的机制。

TCP需要解决的三个基本问题

一个旨在提供可靠传输的协议需要回答三个基本问题:

  1. 何时发送新数据? 即何时发送从未放入网络的数据。
  2. 何时重传数据? 即何时重新发送之前已发送但可能丢失的数据。
  3. 何时发送确认? 即何时通知对方已成功接收数据。

本质上,这些问题决定了协议何时生成数据包、重传包或确认包。在TCP中,确认信息是包头中的一个字段,可以与数据合并发送,但为了简化分析,我们常将数据流和确认流视为独立的单向流。

TCP Tahoe 之前的算法与问题

在TCP Tahoe之前,TCP的行为相对简单。连接通过握手建立后,发送方会获知接收方的流量控制窗口大小(通过TCP头部窗口字段)。算法如下:

  • 发送方立即发送一整个窗口大小的数据。
  • 为每个发出的数据包启动一个重传计时器。
  • 如果在计时器超时前未收到该数据包的确认,则重传该数据包。

这种方法的核心问题是:如果流量控制窗口远大于网络的实际支持能力,发送方在开始时就会向网络“倾倒”大量数据。这就像虽然你的目的地有30MB的存储空间,但你并不想立即将30MB的数据全部灌入你较慢的DSL或电缆调制解调器链路中。

以下是实现该算法可能发生的情况:

  • X轴表示时间(秒),Y轴表示TCP发送字节的序列号(以KB为单位)。
  • 连接建立后,TCP立即发送了约20KB的数据(一个满窗口)。
  • 随后,它因等待确认而阻塞,直到某个数据包超时重传。
  • 图中呈现出巨大的“锯齿”模式:一段密集的数据包流之后,跟着一段因超时而空闲的时期。
  • 许多数据包被重复传输多次。
  • 总体来看,有效数据传输的斜率很低,性能远未达到链路应有的容量。这是因为协议在不必要地发送大量重传,并经历了许多超时。

Van Jacobson 的三大改进

基于上述问题,Van Jacobson 提出了三大改进:

  1. 拥塞窗口 的概念。
  2. 更准确的超时估计
  3. 自计时

本节我们将重点讨论拥塞窗口及相关机制,超时估计和自计时将在后续课程中介绍。

拥塞窗口与发送窗口

基本思路是:流量控制窗口仅关乎接收端的能力,而发送方还需要估计一个拥塞窗口,它代表了网络当前能够支持的数据量。

因此,实际的发送窗口大小取值为:
发送窗口 = min(流量控制窗口, 拥塞窗口)
这个公式的意义在于:发送比网络支持更快的数据没有意义,发送比接收方能处理更快的数据也没有意义。

发送方的行为将基于这个拥塞窗口的大小来调整,并将拥塞窗口的管理分为两种状态。

慢启动状态

第一种状态称为慢启动。它在连接刚开始时,或者在发生数据包超时(表明出现严重问题)后使用。目的是让发送方从低速开始,快速探测出网络的可用容量。

慢启动的基本原理如下:

  • 初始时,拥塞窗口被设置为 1个最大报文段 的大小(即1个MSS)。
  • 之后,每收到一个新的确认,拥塞窗口就增加 1个MSS

这意味着在实践中:

  • 第一个往返时间:发送1个包 -> 收到确认 -> 拥塞窗口变为2。
  • 第二个往返时间:发送2个包 -> 收到2个确认 -> 拥塞窗口变为4。
  • 第三个往返时间:发送4个包 -> 拥塞窗口变为8。
  • ...

由此可见,拥塞窗口呈指数增长。虽然名为“慢启动”,但这是相对于旧版本一开始就发送满窗口数据而言的。通过这种指数增长,可以在对数级步数内快速逼*网络的拥塞点。

拥塞避免状态

第二种状态称为拥塞避免。当发送方认为其发送速率已经接*网络容量时,进入此状态。目标是谨慎地探索网络极限,并保持在一个稳定、高效的发送速率附*,避免引发拥塞。

在拥塞避免状态下,窗口增长规则变为:

  • 每收到一个新的确认,拥塞窗口增加 (MSS * MSS) / 拥塞窗口

这种做法的效果是,在每个往返时间内,拥塞窗口大约只增加 1个MSS。也就是说,窗口从指数增长转变为线性增长,增长步伐大为放缓。

TCP Tahoe 状态机与转换规则

现在,我们将慢启动和拥塞避免结合起来,看看TCP Tahoe如何在这两种状态间转换。其行为由以下几个关键参数和信号控制:

  • 拥塞窗口: 发送方根据网络状况估计的窗口。
  • 慢启动阈值: 一个状态切换的门槛值。
  • 三个关键信号
    1. 正常确认: 数据传输顺利,可以尝试增加窗口。
    2. 三个重复确认: 表示可能有单个数据包丢失(因为TCP使用累积确认,对同一序列号的多次确认意味着后续数据包已到但前面有包缺失)。
    3. 超时: 表示发生了严重问题,可能网络严重拥塞或路径中断。

以下是TCP Tahoe的有限状态机描述:

  1. 初始与慢启动
    • 连接开始时,处于慢启动状态,设置 拥塞窗口 = 1 MSS,并设置一个初始的慢启动阈值
    • 在慢启动状态下,每收到一个确认,执行 拥塞窗口 += 1 MSS
    • 拥塞窗口 增长到超过 慢启动阈值 时,状态转换为拥塞避免

  1. 拥塞避免
    • 在拥塞避免状态下,每收到一个确认,执行 拥塞窗口 += (MSS * MSS) / 拥塞窗口,实现线性增长。
    • 如果在此状态下发生超时或收到三个重复确认,则意味着可能发生了拥塞。

  1. 响应拥塞
    • 一旦检测到拥塞(超时或三个重复确认),TCP Tahoe会采取激进措施:
      • 设置新的 慢启动阈值 = 当前拥塞窗口 / 2
      • 重置 拥塞窗口 = 1 MSS
      • 状态切回慢启动

这个过程可以理解为:每当TCP认为当前发送速率过高导致拥塞时,它就“退避”到起点(慢启动),但记录下之前拥塞点的一半作为新的目标阈值。然后通过慢启动指数增长快速接*这个新阈值,达到后再通过拥塞避免线性增长谨慎探索。这样就能动态地适应网络变化,将发送速率维持在接*但不超越网络容量的水*。

总结

在本节课中,我们一起学习了TCP拥塞控制的核心思想以及TCP Tahoe协议的具体实现机制。

我们首先了解了拥塞控制的动机:防止发送速率超过网络承载能力,避免性能下降。然后回顾了TCP发展史上出现的“拥塞崩溃”问题,这催生了Van Jacobson的改进方案。

TCP Tahoe的核心创新是引入了拥塞窗口,并将发送窗口限制为接收方窗口和拥塞窗口的最小值。它通过慢启动拥塞避免两种状态来管理拥塞窗口:

  • 慢启动阶段,窗口指数增长,用于快速探测网络容量。
  • 拥塞避免阶段,窗口线性增长,用于谨慎维持在容量附*。
  • 通过慢启动阈值三个重复确认/超时信号在两种状态间切换。一旦检测到拥塞,立即大幅减小窗口并重新慢启动。

这套机制使得TCP能够有效利用网络带宽,同时保持稳定性和公*性,是后续所有TCP拥塞控制算法的基础。在接下来的课程中,我们将继续探讨TCP Reno等版本对Tahoe的改进。

计算机网络原理 P6:分组交换原理 📦

在本节课中,我们将要学习互联网设计的核心思想之一:分组交换。我们将了解什么是数据包,分组交换如何工作,以及它带来的两大关键优势。


概述

互联网最初的设计基于一个具有革命性的想法:分组交换。如今,这似乎是构建网络的直接方式,但情况并非总是如此。分组交换是一个简单的想法,但将其付诸实践会产生许多深远的影响。本课程将用一整周的时间讨论分组交换及其影响,而本视频将介绍其高级理念及其带来的直接好处。


什么是数据包?📦

数据包是一个自包含的单位,它包含了到达目的地所需的所有必要信息。

数据包定义:一个包含所有必要信息以使其到达目的地的自包含单位。


什么是分组交换?🔄

上一节我们介绍了数据包,本节中我们来看看分组交换的核心概念。

分组交换是指我们将数据分割成离散的、自包含的数据块。每个数据块被称为一个数据包,它包含足够的信息,使得网络能够将每个数据包送达目的地。

分组交换定义:将数据分成离散的、自包含的数据块(即数据包)进行传输。


分组交换如何工作?🛣️

了解了基本概念后,我们来看看分组交换在实际网络中是如何运作的。

假设我们有一个源点(A)、一个目的地,以及一个由节点B和C组成的包交换网络。当A接收到发往目的地的数据包时,它将其发送到链路B。当B接收到该数据包时,它将其发送到C。当C接收到数据包时,它将其直接发送到目的地。在分组交换的最简单形式中,每个数据包都是被单独且独立地路由的。

例如,假设还有一个连接到B的交换机D。在向C发送一个数据包后,B可以立即向D发送下一个数据包。或者,如果下一个数据包也是发往目的地的,B可以连续发送两个数据包。

以下是分组交换的一个简单操作定义:

  • 对于每个到达的数据包,我们选择其出站链路。
  • 如果链路空闲,我们就发送它。
  • 否则,我们将数据包保留下来以备后用。


数据包的路由方式 🧭

上一节我们看到了交换机如何决策,本节中我们来看看数据包是如何知道该去哪里的。

分组交换工作的一种方式是,每个数据包都包含一个明确的路由,指定了沿途每个包交换机的ID,直到目的地。我们称之为自我路由源路由,因为源点在发送数据包时就指定了路线。

例如,源点为数据包插入路径 A -> B -> C。然后,目的地将数据包转发给A。A查看数据包头部,看到下一个节点是B,于是将数据包转发给B。B看到下一个节点是C,于是转发给C。C看到最后一个节点是目的地,于是完成转发。

互联网支持这种源路由,但通常默认关闭,因为它会引发重大的安全问题。


更高效的路由:转发表 📋

源路由需要携带完整路径,效率不高。一个简单的优化(也是当今互联网主要采用的方式)是在每个交换机中存放一小部分状态。

这个状态通常是一个转发表,它告诉交换机应该将数据包发送到哪个“下一跳”。例如,交换机可以拥有一张表,其中包含目的地地址和对应的下一跳地址。当它接收到一个数据包时,就在表中查找目的地地址,并将数据包发送到相应的下一跳。

在这种模型中,所有数据包只需要携带目的地地址。沿途的每个交换机都可以根据这个地址和本地转发表做出正确的转发决策。

例如,在我们的网络中:

  • 交换机A的转发表指出:发往目的地的数据包应去往交换机B。
  • 交换机B的转发表指出:发往目的地的数据包应去往交换机C。


分组交换的两大优势 ✨

了解了分组交换的工作机制后,我们来看看它带来的两个非常重要的属性。

优势一:交换机简单高效

第一个优势是交换机可以为每个数据包做出独立的本地决策。它不需要在数据包上保持额外的状态。交换机看到两个数据包去往同一个目的地,但它不需要知道这两个数据包是否是某个更大传输协议(如一次文件传输)的一部分。交换机也不需要了解数据包的内容——它不需要知道哪些数据包是Skype通话,哪些是网页请求,哪些是固件更新。它只是简单地转发数据包。

这极大地简化了交换机的设计和实现。

优势二:高效共享链路资源

第二个优势是它让我们能够有效地将链路资源共享给多方。

例如,考虑家庭无线路由器。有两个人在各自的笔记本电脑上浏览网页。如果一个人正在阅读页面(此时不产生流量),那么另一个人可以以全速下载文件。如果第一个人开始加载新网页,链路容量就可以在两人之间共享。一旦下载完成,第一个人又可以使用链路的全部容量。


深入探讨优势一:无状态转发 🧠

这两个优势非常重要,让我们更深入地探讨第一个方面:无状态转发。

当我们通信时,通常不只发送一个数据包,而是发送许多个。例如,一次语音通话由许多连续的数据包组成,它们都属于同一次通信。我们称这一系列数据包为一个流量

更具体地说,一个流量是属于同一端到端通信的一组数据包,例如一个TCP连接。

分组交换的核心在于每个数据包都是独立路由的。因为每个数据包都是自包含的,交换机不需要知道关于数据包组或“流量”的任何信息。

试想一下,如果每个交换机都必须跟踪经过它的每一个Web连接,这将需要巨大的状态,并且非常难以管理。相反,独立处理每个数据包意味着交换机可以建造得更简单、更易于管理和调试。交换机不需要担心添加或删除“流”的状态。

想象一下,如果你每次想加载一个网页,都需要与路径上的每个交换机通信,只为设置状态以便你的请求能通过。这可能会使事情变得慢得多。而使用分组交换,你只需要发送数据包,交换机就会转发它们。

交换机也不需要存储这种“流”状态。因为交换机必须非常快,它们需要将状态存储在非常快速的内存中,这将是昂贵的。分组交换允许交换机只专注于一件事:快速高效地转发数据包。

最后,这意味着交换机不需要担心故障。例如,当你开始一个Web请求时,如果你的*板电脑突然没电了,在需要维护“流”状态的系统中,交换机将一直保留这个请求的流状态。如果创建状态的节点之一失败,交换机需要知道如何清理后果,否则内存中可能会堆积大量无效的“死亡”流状态。

而使用分组交换,交换机没有针对每个终端或每个流的状态。如果你的*板电脑关机了,交换机并不关心,它只是停止从那里接收数据包。这样,交换机在功能上就独立于通过它发送流量的计算机。


深入探讨优势二:统计复用 📊

上一节我们讨论了无状态转发如何简化交换机,本节我们来看看第二个优势:高效的资源共享,这被称为统计复用

想想你通常如何使用互联网:你的使用是间歇性的。你加载一个网页,然后阅读它,再加载另一个。你从iTunes下载几首歌,然后听歌。你从Netflix流式传输节目45分钟,然后停止。数据流量并非总是以固定速率发送和接收,其使用率会随时间起伏。

在宏观上,流量模式会大规模变化(例如,下午两点通常很高,晚上八点不错,凌晨两点很低)。在微观上,流量非常具有突发性,而且不同用户的突发往往是独立的。

假设你和你的朋友都在咖啡店浏览网页。当你加载新页面时,你的朋友可能在阅读;当你的朋友加载新页面时,你可能在阅读。大多数时候你们的流量是独立的,有时可能会重叠,但往往不会。

因为路由器将所有流量都视为独立的数据包,所以它可以非常有效且简单地在你们之间共享其容量。

  • 如果你正在加载页面而你的朋友在阅读,无线路由器可以将其全部容量分配给你的数据包。
  • 如果你的朋友正在加载页面而你在阅读,路由器可以将其全部容量分配给你朋友的数据包。
  • 如果你们俩同时都在使用,那么链路容量将由你们共享。

这种根据概率或统计方式将单个资源分配给多个用户的想法,就叫做统计复用。它是“统计的”,因为每个用户根据其他人如何使用资源而获得一个统计上的份额。例如,如果你的朋友正在阅读,你可以使用全部链路;如果你们俩都在加载页面,你*均获得大约一半的链路容量。


总结 🎯

本节课中我们一起学习了分组交换的原理。我们了解到:

  1. 数据包是包含目的地信息的自包含数据单元。
  2. 分组交换是将数据分割成数据包进行独立传输和路由的过程。
  3. 路由可以通过源路由(数据包携带完整路径)或更常见的查表转发(交换机根据目的地地址查找转发表)实现。
  4. 分组交换有两大核心优势:
    • 使交换机简单高效:交换机无需维护每个“流”的状态,只需独立转发每个数据包,简化了设计、管理和故障处理。
    • 实现统计复用:允许网络链路根据用户的实际需求动态、高效地在多个用户之间共享容量,提高了资源利用率。

这个简单的构建块在当时是革命性的,并构成了当今互联网的基础。

课程 P60:TCP RTT 估计与自我时钟机制 🕐

在本节课中,我们将学习 TCP Tahoe 协议为解决网络拥塞崩溃问题而引入的另外两项核心改进:RTT(往返时间)估计自我时钟机制。上一节我们介绍了拥塞窗口和慢启动/拥塞避免状态机,本节中我们来看看 TCP 如何更智能地决定何时重传数据,以及如何通过确认机制来调节发送速率。


概述 📋

TCP Tahoe 对早期网络拥塞崩溃问题进行了三项主要改进。我们已经学习了第一项:将拥塞窗口集成到慢启动和拥塞避免两个操作状态中。本课程将详细解释其余两项关键机制:

  1. RTT 估计:如何动态、准确地计算重传超时(RTO)值。
  2. 自我时钟:接收方如何通过确认(ACK)来自然地调节发送方的数据发送节奏。

准确估计重传超时对 TCP 行为有显著影响。超时过长会导致传输停滞,等待不必要的确认;超时过短则会导致不必要的重传和激进地退回到慢启动状态。TCP Tahoe 的改进方法已成为估计网络系统中噪声信号的通用好方法。


RTT 估计的重要性 ⚖️

因为 TCP 在超时后会过渡到慢启动状态,所以拥有一个良好的超时值至关重要。

如果往返时间(RTT)是常数,那么最佳传输超时(RTO)只需比 RTT 略大一点。因为成功接收数据包的确认(ACK)应该在数据包传输后的 RTT 时间间隔内到达。

但是,RTT 不是常数。它们可以高度动态变化。此外,随着数据流发送数据段并开始填充沿途路由器的队列,RTT 会因负载发生显著变化。其他流量源的突发也可能显著改变队列延迟。面对所有这些噪声,我们需要一种稳健的方法来估计在假设数据包丢失之前应等待多久。


早期 TCP 的 RTT 估计方法

在 TCP Tahoe 之前,TCP 跟踪一个单一变量 R 作为其 RTT 估计。

每次收到一个新的确认时,它会计算一个 RTT 测量值 M(即从发送数据段到接收确认的时间间隔)。

R 是这些测量值的指数加权移动*均(EWMA)。公式如下:
R = α * R + (1 - α) * M
(其中 α 是一个*滑因子,通常接* 1,如 0.875)。

如果没有在 2R 时间内收到对某个数据段的确认,TCP 就假设它丢失并触发重传。

那么这个方法的问题在哪里?

基本问题是,它假设 RTT 测量的方差是其值的一个常数因子(即固定为 2 倍)。这无法适应多变的网络环境。


TCP Tahoe 的改进:引入方差估计

因此,TCP Tahoe 在其重传超时计算中集成了对延迟方差的估计。

它保持对 RTT 估计 R 的指数加权移动*均(与之前相同)。

它还测量当前测量值 M 与估计值 R 的差异程度,即估计误差 Err = M - R

它对这个误差的绝对值(代表方差)应用另一个指数加权移动*均,得到变量 V(方差估计)。

最终,它按以下公式计算重传超时(RTO):
RTO = R + 4 * V

所以,如果连接的 RTT 非常稳定,方差 V 小,超时时间只会稍微大于*均 RTT。但如果 RTT 变化较大,V 值会增大,TCP 就会选择一个更大的超时时间,避免不必要的重传。

如果重传失败(即重传的数据包仍未被确认),那么 TCP 会以指数增加的定时器再次重传(例如,将 RTO 翻倍)。TCP 假设这意味着存在严重的拥塞,因此通过增加重传间隔来继续其“乘法减少”的退避策略。

参数 α(用于 RTT *滑)和 β(用于方差*滑,以及 RTO 公式中的倍数 4)是通过实验选择的。这种方法相对稳健,对它们进行微小更改并没有特殊的魔力,它们只是在实践中工作得很好。


效果对比

原始 TCP 拥塞控制论文中的图表显示,TCP Tahoe 之前的算法非常保守。测量值和超时值之间的大差距代表浪费的等待时间。同时,当 RTT 出现尖峰时,旧算法会导致不必要的重传和进入慢启动。

相比之下,TCP Tahoe 的 RTT 估计值(图中顶部的暗线)更紧密地跟踪实际的 RTT 测量值(底部的亮线),从而做出更合理的重传决策。


自我时钟机制 ⏱️

现在我们已经回答了第二个问题(TCP 何时重传数据),我们来到第三个问题:TCP 应该在何时发送确认?

答案是:一般来说,尽可能少地延迟,即一旦收到数据段就立即发送确认。

如果 TCP 遵循这个策略,将导致一个非常重要且强大的行为,被称为自我时钟

自我时钟意味着:如果接收方积极发送确认,那么这些确认会按照数据包离开网络瓶颈链路的速率在时间上分散到达。发送方在收到确认后才会发送新数据,因此它将以瓶颈链路所能支持的速率发送数据段。

这项政策有一个额外的好处:TCP 只有在收到确认(意味着它的一个现有数据包已从网络拥塞角度离开)时才将新数据包放入网络。这意味着 TCP 正在控制网络中未完成数据包的数量,从而稳定队列并有效利用网络容量。

所以,自我时钟原理要求 TCP 一旦收到数据段就积极发送确认。这既是为了向发送方信号数据已经离开网络,也是为了提供 RTT 估计并允许发送方根据网络状况自我调节其传输速率。


总结 🎯

本节课中,我们一起学习了 TCP Tahoe 协议的三项核心拥塞控制机制中的后两项:

  1. 智能的 RTT 估计:TCP Tahoe 不仅计算 RTT 的指数加权移动*均值(R),还估计其方差(V)。重传超时(RTO)由公式 RTO = R + 4 * V 计算得出。这使得超时值能自适应网络延迟的波动,减少误判。
  2. 自我时钟:接收方立即发送确认的策略,使得确认的到达节奏反映了网络的可用带宽。发送方据此节奏发送新数据,实现了传输速率与瓶颈带宽的自动匹配,并控制了网络中的在途数据量。

结合上一课的拥塞窗口状态机,这三项机制共同使 TCP Tahoe 能够有效地管理网络拥塞,在繁忙的网络中获得良好性能。从这项设计中我们可以学到,在设计需要估计重传或重试时间的网络协议时,不仅要考虑观察到的*均延迟,还必须考虑其方差。

课程 P61:TCP Tahoe 的 RTT 估计与自时钟机制 ⏱️

在本节课中,我们将学习 TCP Tahoe 协议中引入的两个关键机制:往返时间估计自时钟。这些机制与拥塞窗口、慢启动等概念共同构成了 TCP 的拥塞控制基础,使得互联网能够稳定工作。


回顾 TCP Tahoe 的三个基本机制

上一节我们介绍了 TCP Tahoe 的三个基本机制,它们共同实现了拥塞控制。本节中,我们来看看其中两个更深入的机制:RTT 估计和自时钟。


RTT 估计的重要性

往返时间估计对于重传和超时至关重要。如果 RTT 估计过短,会导致不必要的重传,浪费网络容量并可能错误触发慢启动。如果 RTT 估计过长,则会在数据包实际丢失后等待过久才重传,降低效率。

在分组交换网络中,RTT 是高度动态变化的,网络负载的变化也会显著影响延迟。因此,需要一个能够快速、准确估计路径延迟的算法。


简单的 RTT 估计算法及其问题

在 TCP Tahoe 之前,使用一种简单的估计算法。该算法维护一个 RTT 估计值 r,并通过指数加权移动*均来更新它。

以下是该算法的核心公式:

r = α * r + (1 - α) * m

其中:

  • r 是当前的 RTT 估计值。
  • m 是最*一次测量的 RTT 值。
  • α 是历史样本的权重因子(0 < α < 1)。α 值越高,表示越重视历史数据;α 值越低,表示越重视最新测量。

超时时间则设置为 β * r,通常 β = 2。这意味着,如果超过两倍的*均估计时间仍未收到确认,就触发超时。

然而,这种方法存在一个问题:它只考虑了 RTT 的*均值,而没有考虑其方差。对于 RTT 分布很集中的连接,β=2 过于保守,会导致不必要的等待。对于 RTT 分布很分散的连接,β=2 又过于激进,会导致大量不必要的重传。


TCP Tahoe 的改进:引入方差估计

TCP Tahoe 通过将 RTT 的方差概念纳入估计,解决了上述问题。算法不仅计算 RTT 的指数加权移动*均,还计算估计误差的指数加权移动*均方差。

以下是改进后的估计算法步骤:

  1. 计算*均 RTT
    Err = M - R
    R = R + g * Err
    
  2. 计算*均偏差
    D = D + h * (|Err| - D)
    
  3. 设置超时时间
    Timeout = R + 4 * D
    

其中:

  • R 是估计的*均 RTT。
  • M 是最*一次测量的 RTT。
  • Err 是测量误差。
  • D 是*均偏差(方差的*似)。
  • gh 是增益因子(通常 g=1/8, h=1/4)。
  • 超时时间设置为 R + 4 * D

这样,当 RTT 分布集中(方差 D 小)时,超时时间接* R,可以快速响应丢包。当 RTT 分布分散(方差 D 大)时,超时时间会显著大于 R,避免因网络抖动而误判丢包。


自时钟机制

TCP Tahoe 的第三个重要改进是自时钟机制。这是其最伟大的概念贡献之一。

自时钟的核心思想是:根据接收到的确认来定时发送新的数据包。其概念模型如下:

  1. 发送方有一个“大管道”,可以快速产生数据包。
  2. 网络中间存在一个瓶颈链路。
  3. 快速发送的数据包经过瓶颈链路时会被“拉伸”,在时间上间隔开来到达接收方。
  4. 接收方每收到一个数据包,就发送一个确认。
  5. 这些确认包经过瓶颈链路返回发送方时,其到达间隔反映了接收方收到数据包的间隔,即瓶颈链路允许的速率。
  6. 发送方只有在收到一个确认后,才发送一个新的数据包。

通过这种方式,发送方发送数据包的速率会自动匹配网络瓶颈链路所能处理的速率,从而避免一次性注入大量数据包导致队列溢出和拥塞。这实现了“管道填充而不溢出”的目标。

此外,接收方应积极发送确认(例如重复确认),这为发送方提供了重要的网络状态信号(如丢包),并帮助其维持自时钟节奏。


总结与展望

本节课中,我们一起学习了 TCP Tahoe 协议中两个关键的增强机制:

  1. 改进的 RTT 估计:通过引入方差计算,使超时设定更能适应网络抖动的实际情况,减少了不必要的重传和等待。
  2. 自时钟:通过“收到确认再发送新包”的规则,使发送速率自动适应网络瓶颈带宽,从根源上*滑流量,避免拥塞。

这些机制与拥塞窗口、慢启动共同构成了 TCP Tahoe 的拥塞控制框架。Van Jacobson 在1988年发表的关于 TCP Tahoe 的论文里程碑式地解决了当时互联网的拥塞崩溃问题。

在接下来的课程中,我们将了解 TCP 拥塞控制的后续发展,如 TCP Reno 和 NewReno,它们引入了快速重传、快速恢复等新机制,进一步优化了性能。

课程 P62:TCP 拥塞控制 - Reno 与 New Reno 🚦

在本节课中,我们将学习 TCP 拥塞控制的两个重要改进版本:TCP Reno 和 TCP New Reno。我们将了解它们如何通过“快速重传”和“快速恢复”等机制,在保持网络稳定的同时,显著提升数据传输的性能。


TCP Tahoe 的回顾与局限

上一节我们介绍了 TCP Tahoe 的基本拥塞控制机制。TCP Tahoe 解决了拥塞控制的基本问题,使得 TCP 能够在互联网上稳定运行。

然而,TCP Tahoe 并不总能达到最佳性能,它的行为有时过于保守。

因此,在 TCP Tahoe 之后,TCP 协议有了进一步的改进,尽管其核心机制依然被保留。

为了获得更高的性能和更快的发送速度,我们接下来将介绍两个重要的改进版本。


TCP Reno 的改进 🚀

TCP Reno 的行为通常与 TCP Tahoe 类似,但有一个关键例外。这个例外体现在对“三次重复确认”事件的处理上。

以下是 TCP Tahoe 在遇到拥塞事件(超时或三次重复确认)时的行为:

  1. 将慢启动阈值设置为当前拥塞窗口的一半。
  2. 将拥塞窗口重置为 1。
  3. 重新进入慢启动阶段。

TCP Reno 与 TCP Tahoe 的不同之处在于处理三次重复确认时。它假设只有一个数据包丢失,而其他数据包仍在正常到达,因此网络状况可能并没有那么糟糕。

所以,TCP Reno 在遇到三次重复确认时:

  1. 将慢启动阈值设置为当前拥塞窗口的一半。
  2. 将拥塞窗口设置为新的慢启动阈值(即减半),而不是重置为 1。这被称为 快速恢复
  3. 同时,它会立即重传被认为丢失的数据包,这被称为 快速重传,而无需等待超时。

这种行为意味着,在三次重复确认后,TCP Reno 会保持在拥塞避免状态,避免了重新进入慢启动阶段。这使得窗口大小可以保持在一个更高的水*,并且由于快速重传,它不会浪费几个往返时间来等待超时。

因此,TCP Reno 的整体吞吐量比 TCP Tahoe 更高。


TCP Reno 行为图示

以下图示展示了 TCP Reno 在类似情况下的行为。

我们从慢启动状态开始,拥塞窗口指数增长。当遇到三次重复确认时,拥塞窗口减半(而不是降为1),并进入快速恢复和快速重传。之后,它直接回到拥塞避免状态,继续线性增长。

如果遇到超时事件,TCP Reno 的行为则与 Tahoe 相同:将拥塞窗口重置为 1,并重新开始慢启动。


TCP New Reno 的进一步优化 ⚡

TCP New Reno 在超时处理上的行为与 Reno 和 Tahoe 相同。它的主要改进在于处于“快速恢复”状态时,对拥塞窗口进行了一些更复杂的调整。

当你因三次重复确认而进入快速恢复状态时:

  1. 对于后续收到的每一个重复确认,都将拥塞窗口临时增加一个最大报文段的大小。
  2. 当收到对丢失数据包的重传确认(即一个新的、非重复的确认)时,退出快速恢复状态,并将拥塞窗口恢复为进入快速恢复时设置的值(即减半后的值)。

这样做的目的是:当我们有一大批数据包在等待确认,而其中一个丢失时,后续到达的重复确认表明数据包仍在离开网络。通过临时膨胀拥塞窗口,允许发送方在等待重传确认的同时,继续发送新的数据包,从而避免了在往返时间内管道空闲。

一旦收到正确的重传确认,拥塞窗口会立即恢复到正确的大小,不会导致网络突然过载。


核心机制总结

本节课中我们一起学习了 TCP Reno 和 New Reno 如何优化拥塞控制:

  • 快速重传:在收到三次重复确认后,不等待超时就立即重传可能丢失的包。
  • 快速恢复:在三次重复确认后,将拥塞窗口减半并保持,而不是重置为1,从而避免退回到慢启动。
  • 窗口膨胀:在快速恢复期间,通过重复确认临时增大窗口,以保持数据流,提高吞吐量。

这些机制的核心思想是:乘性减,加性增。当网络出现问题时反应迅速(乘性减),在网络良好时谨慎增加(加性增)。快速重传避免了等待超时的延迟,而窗口膨胀则避免了在重传期间管道空闲。

如今,许多操作系统(如 Linux、Windows、macOS)中使用的基础 TCP 算法都与 Reno 非常相似,这些机制共同构建了一个既健壮又高效的网络传输系统。

计算机网络课程 P63:TCP Reno 详解 🚀

在本节课中,我们将学习 TCP 协议中两种重要的性能改进机制:快速重传快速恢复。我们将详细探讨它们如何与 TCP Tahoe 和 TCP Reno 协同工作,以更高效地处理网络拥塞和数据包丢失。


概述 📋

除了拥塞避免、RTT 估计和自我时钟机制,TCP 还使用了三种额外的机制来提升性能。这些机制通过软化 TCP 对数据包丢失的反应来实现。回忆 TCP Tahoe 的行为,它在面对数据包丢失时比 AIMD 策略更为保守。

TCP Tahoe 在检测到丢失时会进入慢启动状态。当拥塞窗口达到慢启动阈值时,它会指数级增加窗口大小。到达该点后,它进入加性增加阶段。


快速重传机制 ⚡

第一个机制称为快速重传,它是 TCP Tahoe 的一部分。

如果 TCP Tahoe 发送方收到三个重复的确认(即对于同一个序列号有四个 ACK),它会假设下一个数据段已丢失并立即重传。发送方无需等待超时,从而减少了接收确认前的延迟,并可以向前移动发送窗口以发送新数据。

TCP Tahoe 将这三个重复确认视为数据包丢失,并设置拥塞窗口为 1,进入慢启动状态。


快速恢复机制 🔄

TCP Reno 是 TCP 的一个后续版本,它引入了第二种算法,称为快速恢复。该算法包含两个主要机制。

第一个机制是:当通过三个重复确认检测到数据包丢失时,TCP Reno 不会将拥塞窗口设置为 1,也不会进入慢启动状态。相反,它将拥塞窗口减半,并将慢启动阈值设置为当前拥塞窗口的一半。这意味着 TCP Reno 保持在拥塞避免状态。

使用此算法,在无超时的稳定状态下,TCP Reno 在遇到丢失时遵循 AIMD 策略:它执行拥塞窗口乘法减少,并在超时时使用加法增加。在超时情况下,TCP Reno 的行为与 TCP Tahoe 相同,将拥塞窗口重置为 1。

第二个机制是:当处于快速恢复状态时,TCP Reno 会为每个收到的重复确认将拥塞窗口增加 1。这是为了防止在单个数据包丢失的情况下,TCP 因等待确认来推进发送窗口而无法在整个往返时间内发送数据。

因为每个重复确认意味着一个数据段已成功离开网络,理论上,TCP 可以在不阻塞网络的情况下发送一个新数据段。假设旧的拥塞窗口大小为 c,当拥塞窗口因每个重复确认增加 1 时,窗口大小会从 c/2 增长到 c + c/23c/2

这意味着,对于从 c/2c 的重复确认,TCP 可以发送一个新数据段。一旦 TCP 接收到一个新的确认,它会将拥塞窗口重置为正确的值,即 c/2


TCP Tahoe 与 TCP Reno 行为对比

上一节我们介绍了两种机制的核心概念,本节中我们来看看它们的具体行为差异。

以下是 TCP Tahoe 在遇到超时或三个重复确认时的处理步骤:

  1. 将慢启动阈值设置为当前拥塞窗口的一半。
  2. 将拥塞窗口设置为 1。
  3. 重传丢失的数据段。

第一步意味着 TCP Tahoe 进入了慢启动状态,并会指数级增加其拥塞窗口,直到再次遇到数据包丢失或达到慢启动阈值。这导致了我们在早期图表中看到的 TCP Tahoe 随时间变化的行为。

现在,让我们走一遍 TCP Tahoe 在遇到三个重复确认时的具体流程。假设拥塞窗口是 8 MSS,一个数据段丢失了。TCP 将总共收到 7 个重复确认。在收到第三个重复确认后,它会重传丢失的数据段,将拥塞窗口设置为 1 MSS,并将慢启动阈值设置为 4。

当它收到重传数据段的确认时,会发送一个新数据段。当收到对这个新数据段的确认时,它将拥塞窗口设置为 2。当收到对这两个数据段的确认时,它会将拥塞窗口增加到 3,然后是 4。

当拥塞窗口达到慢启动阈值时,它进入拥塞避免状态。接下来的四个确认只会使拥塞窗口增加 1 MSS。这就是 TCP Tahoe 的行为。


TCP Reno 的行为流程

TCP Reno 在超时时的行为与 TCP Tahoe 相同。但在收到三个重复确认时,它会执行快速重传,立即发送数据段,而不是将拥塞窗口设置为 1。它会将拥塞窗口减半,从而保持在拥塞避免状态。

对于每个重复确认,它会将拥塞窗口增大 1,以便在重传的数据段被确认之前发送新的数据段。因此,Tahoe 和 Reno 的主要区别在于快速恢复机制。

以下是一幅显示 Reno 行为的图表。它从慢启动状态开始。当遇到三个重复确认时,它将拥塞窗口减半,保持在拥塞避免状态,并执行快速重传。然后开始使用 AIMD 策略增加拥塞窗口。

在快速恢复期间,它使用拥塞窗口膨胀来发送新的数据段。在第二组三个重复确认中,相同的情况发生:它执行快速重传,将窗口减半并保持在拥塞避免状态。在超时时,它将拥塞窗口设置为 1 并重新进入慢启动状态。

拥塞窗口膨胀是快速恢复的一部分。以下是 Reno 进入快速恢复时如何工作的详细信息:它可以通过每个重复确认将其拥塞窗口增加 1。因为拥塞窗口已经减半,这意味着拥塞窗口可以增长到其原始值的一半以上。

具体来说,发送者将发送大约 原始拥塞窗口 / 2 个新数据段(减去一个丢失的数据段),这几乎等于遵守 AIMD 策略所需的量。


状态机对比

回忆一下,TCP Tahoe 的有限状态机有两个状态:慢启动拥塞避免

TCP Reno 的全部 FSM 在三个重复确认时添加了第三个状态:快速恢复。它不会过渡到慢启动,而是过渡到快速恢复状态。当它收到新的确认时,它会过渡回拥塞避免状态,并将拥塞窗口重置为之前大小的一半。

当它在快速恢复状态中超时时,它会返回慢启动状态。就像在拥塞避免状态收到重复确认时一样,在快速恢复状态中,它也会将拥塞窗口增加 1。在快速恢复的初始过渡中增加 3,是为了考虑到已经收到的三个重复确认。


TCP Reno 行为示例

让我们走一遍 Reno 的具体行为。假设我们开始时拥塞窗口大小为 8 MSS,一个数据段被丢弃。发送者将在第一个三个重复确认后,总共收到七个重复确认。

  1. 它将拥塞窗口缩小为剩余的一半,即 4 MSS,并保持在拥塞避免状态。
  2. 在快速恢复期间,对于接下来的重复确认,它会将拥塞窗口扩大。经过三次增加(对应三个重复确认),窗口增长到 7 MSS。
  3. 在第四次重复确认时,拥塞窗口增长到 8 MSS。
  4. 接下来的三个确认将使窗口增加到 9、10,然后 11 MSS。这样,发送者大约可以在这个时候发送三个新的数据段。
  5. 当发送者收到对重传数据段的确认时,这个确认号会将发送窗口向上移动,以包含触发所有重复确认的数据段。
  6. 此时,TCP Reno 会将拥塞窗口缩小到正确的值,即其旧值的一半(4 MSS)。这允许 TCP Reno 发送一个新的数据段。

总结与思考 💡

在本节课中,我们一起学习了 TCP Reno 如何通过快速重传快速恢复机制来改进网络性能。这两种机制使 TCP 在面对数据包丢失时能做出更快速、更温和的反应,避免了像 TCP Tahoe 那样激进地退回到慢启动状态,从而在大多数情况下保持了更高的吞吐量。

拥塞控制是一个非常复杂的问题。需要记住的是,它并非人们最初预期的那样简单。它是早期互联网开发者和用户观察到的一种必须面对的涌现行为,目的是为了使互联网能够稳定工作。

TCP 今天使用的基本方法是 AIMD,但关于它如何工作有很多细节。TCP 具体如何发送数据、何时重传数据以及如何发送确认,都需要在实际应用中处理一系列边缘情况,才能使 AIMD 策略良好且稳定地工作。

如今,几乎所有 TCP 变种都基于 TCP Reno,并添加了一些处理现代网络高速特性的功能。当你连接到最喜欢的网站时,你的操作系统很可能正在使用 TCP Reno 及其慢启动和拥塞避免机制。

课程 P64:TCP 拥塞控制 - AIMD 原理详解 🚦

在本节课中,我们将学习 TCP 拥塞控制的核心机制之一:加性增、乘性减。我们将探讨它为何能有效*衡网络利用率和用户公*性,并通过图形化方式直观理解其工作原理。


概述:网络中的冲突需求

网络中存在两种相互冲突的需求。

服务提供商希望最大化其链路利用率,即希望网络被完全利用,没有空闲容量。

用户则希望公*地分享网络资源。如果只有一个用户占用了整个管道,其他用户会不满意。

因此,拥塞控制算法的目标是:让链路运行在接*满载的利用率,同时收敛到每个用户(在条件相同时)大约获得 1/n 的公*份额(假设有 n 个用户)。这样既能避免网络崩溃,又能保证数据传输效率。


核心目标与最优窗口

我们希望最大化高利用率链路的使用率,同时确保每个用户公*地分享链路,并防止网络因过载而性能恶化。

那么,拥塞窗口应该设置为多大?实际上,最优的拥塞窗口大小是带宽延迟积

这个基本思想是:如果带宽是每秒 B 字节,延迟是 D 秒,那么有效的窗口大小应为 B * D 字节。

公式:最优拥塞窗口 = 带宽 (B) × 延迟 (D)

例如:

  • 带宽 10 MB/s,延迟 100 ms,则窗口应为 10 MB/s * 0.1 s = 1 MB
  • 带宽 6 MB/s,延迟 90 ms,则窗口应为 6 MB/s * 0.09 s = 540 KB

如果每个连接的拥塞窗口都按此设置,并且有多个连接,它们的总发送速率将等于链路容量。


可视化理解:吞吐量轨迹图

一种理解拥塞窗口如何随时间变化,或者说流量如何竞争网络资源的方法,是使用吞吐量轨迹图

假设网络中有两个竞争流:流量 A 和流量 B。

  • 我们在 X 轴上绘制流量 A 的速率(或拥塞窗口大小)。
  • 我们在 Y 轴上绘制流量 B 的速率。

如果网络完全公*,则 A 的速率等于 B 的速率,所有点应落在 A = B 的公*线上。

如果满足服务提供商的要求,即链路完全利用,则两个流的总和应等于网络容量 C,即 A + B = C。这条线被称为效率线。

理想的拥塞控制算法应能使流量从任意起点开始,最终收敛到公*线与效率线的交点。这个点同时满足了公*性高效率

在效率线右侧意味着网络过载,丢包概率增大,将触发拥塞响应(如收到三个重复ACK)。在效率线左侧则意味着网络负载不足。


AIMD 的工作过程

现在,我们来看加性增、乘性减如何引导流量收敛到理想点。

假设在时间 t1,流量 B 的速率远高于其公*份额,而流量 A 的速率远低于其公*份额。

以下是发生的过程:

  1. 加性增阶段:两者都处于加性增模式,逐步增加其拥塞窗口和发送速率。
  2. 触发过载:直到某个时刻,网络变得过载并开始丢包。
  3. 乘性减阶段:两个流都进行乘性减少(例如,将窗口减半),然后退回。
  4. 再次加性增:减少后,它们重新开始加性增加。

由于乘性减少对速率高的流影响更大(减少的绝对值更多),这使得 t3 时刻的流量对 (A, B)t1 时刻更接*公*线。

随着时间的推移,这种“推进直到轻微过载,然后后退”的振荡过程,在乘性减少的缩放效应下,会使竞争流逐渐收敛到公*线与效率线的交点。

最终,我们将看到多个流量在公*线附*振荡,并随着加性增而接*网络容量,偶尔因过载而后退。加性增、乘性减机制使得一组流量最终能同时获得网络容量的公*份额,并保持链路的高利用率。


总结

本节课我们一起学习了 TCP 拥塞控制中的 AIMD 机制。

我们首先了解了网络中对高效率公*性的双重需求。接着,我们引入了带宽延迟积作为最优拥塞窗口的理论依据。

然后,我们通过吞吐量轨迹图可视化地分析了两个竞争流的行为,明确了理想收敛点是公*性与效率的*衡点。

最后,我们逐步剖析了 AIMD 的工作过程:通过周期性的加性增探索可用带宽,在检测到拥塞时通过乘性减快速降低负载。这种机制能有效地引导网络流量同时实现高利用率和公*分配,是互联网拥塞控制的基石之一。

课程P65:RFC阅读指南 📖

在本节课中,我们将学习如何阅读和理解RFC(Request for Comments,请求评论)文档。RFC是定义互联网协议和标准的核心文档,掌握其阅读方法对于深入理解互联网工作原理至关重要。

RFC是什么?🤔

上一节我们介绍了课程目标,本节中我们来看看RFC的基本概念。

RFC是互联网工程任务组(IETF)发布的一系列技术文档,用于描述互联网协议、标准、最佳实践等信息。它并非强制性的控制声明,而是社区对话和共识的产物。虽然今天的RFC格式比最初更为正式,但其核心精神——作为实现互操作性(即不同系统能够协同工作)的指导——始终未变。

RFC的类型与意义 📋

理解了RFC的基本定义后,我们来看看RFC有哪些不同类型,以及它们各自的意义。

初学者可能会对RFC的多种类型感到困惑。实际上,不同类型的RFC具有不同的意义和对互联网标准过程的影响。RFC主要分为以下几类:

以下是RFC的主要类型:

  • 实验性(Experimental):描述仍在探索阶段的想法或技术。
  • 信息性(Informational):提供对社区有价值的信息,但不定义协议标准。
  • 提议标准(Proposed Standard):一组人认为应该成为互联网通用标准的技术规范。
  • 标准追踪(Standards Track):已成为互联网稳定标准的技术规范。从提议标准过渡到此状态需要经过严格的流程,包括多个可互操作的实现和正式的审核。
  • 最佳当前实践(Best Current Practice, BCP):根据当前知识状态,描述完成某项任务的最佳方法。例如,关于如何实现TCP及其拥塞控制算法的文档就属于此类。

RFC的诞生过程 🚀

上一节我们介绍了RFC的类型,本节中我们来看看一份文档是如何最终成为RFC的。

RFC的制定过程是一个严谨的社区协作流程。以下是一个简化的步骤说明:

以下是RFC从构思到发布的主要步骤:

  1. 个人草案(Individual Draft):文档始于一份个人提交的草案,表明某人或某小组认为此文档可能对互联网有益。例如:draft-levis-ticc-00
  2. 工作组草案(WG Draft):如果草案被相关IETF工作组采纳为工作项目,其名称会变为draft-ietf-工作组名-主题-00,版本号重置。文档在工作组内经过会议讨论、邮件列表反馈和多次修订。
  3. 工作组最后征集(WG Last Call):工作组主席认为文档已成熟,会在工作组内部发起最后征集,以收集最终修改意见。
  4. IETF最后征集(IETF Last Call):文档被提交至整个IETF社区进行最后审查,任何人都可以提出意见。
  5. IESG审核(IESG Review):互联网工程指导组(IESG)进行最终审核。该小组由各领域专家组成,他们可能批准发布,也可能要求重大修改或拒绝。
  6. 发布为RFC:审核通过后,文档被分配一个RFC编号并正式发布。

如何解读RFC中的关键术语 🔑

了解了RFC的制定流程后,阅读具体文档时,理解其使用的特定术语至关重要。

RFC 2119定义了在RFC中用于表示要求级别的关键术语。这些术语通常以大写形式出现,含义如下:

以下是RFC中的核心要求术语:

  • 必须(MUST)/ 必须不(MUST NOT):表示绝对要求。不遵循则意味着不符合RFC规范,无法实现互操作性。
  • 应该(SHOULD)/ 不应该(SHOULD NOT):表示强烈推荐的做法。理解不这样做可能带来的后果后,可以选择不遵循。
  • 可以(MAY):表示完全可选,是否实现不影响互操作性。

实战解析:RFC 5681示例 📄

上一节我们学习了RFC的关键术语,现在让我们通过一个真实案例来应用这些知识。

我们以RFC 5681(TCP拥塞控制)为例。这是一份标准追踪RFC。

文档首先声明,TCP发送方可以(MAY)比算法建议的更保守(发送更慢),但绝不能(MUST NOT)更激进(发送更快)。这设定了行为的上限。

在定义初始拥塞窗口(cwnd)大小时,文档规定:

  • 对于大尺寸报文段,初始窗口必须(MUST)为2个报文段。
  • 对于中等尺寸报文段,初始窗口必须(MUST)为3个报文段。
  • 对于小尺寸报文段,初始窗口必须(MUST)为4个报文段。

在定义初始慢启动阈值(ssthresh)时,文档建议其应该(SHOULD)被设置为一个任意高的值,以便慢启动可以持续到出现丢包为止。这意味着实现者可以设置更低的值,但应该理解其后果。

在拥塞避免阶段,关于增加拥塞窗口的规则是:

  • 发送方可以(MAY)每次往返时间(RTT)增加少于1个报文段的窗口。
  • 发送方应该(SHOULD)每次RTT按以下公式增加1个报文段的窗口:Increase = SMSS * SMSS / cwnd
  • 发送方绝不能(MUST NOT)每次RTT增加超过1个报文段的窗口。

理论与现实的差距 💡

最后,需要明确一点:RFC是技术规范,而非法律条文。

尽管RFC规定了“必须”遵守的条款,但并没有中央机构强制执行。现实中,出于性能等考虑,一些主要厂商可能不完全遵循。例如,有研究发现,谷歌和微软的服务器在建立新连接时,设置的初始拥塞窗口大小超过了RFC 5681的规定,以便更快地传输数据。这引发了关于是否应更新RFC以适应现代网络环境的讨论。这正体现了互联网标准在理想规范与实际部署之间的动态*衡。

总结 📝

本节课中我们一起学习了:

  1. RFC的本质:它是定义互联网互操作性的核心共识文档。
  2. RFC的类型:包括实验性、信息性、提议标准、标准追踪和最佳当前实践等。
  3. RFC的制定流程:从个人草案到IESG批准发布的协作过程。
  4. 关键术语解读必须(MUST)应该(SHOULD)可以(MAY)等术语的精确含义。
  5. 实践与案例:通过RFC 5681分析了具体规范,并理解了标准在现实世界中的应用与变通。

掌握RFC的阅读方法,是深入理解互联网底层协议和参与网络技术社区讨论的重要基础技能。

课程 P66:TCP/IP 协议详解 - 第4.11讲 拥塞控制 🚦

在本节课中,我们将要学习计算机网络中的一个核心概念:拥塞控制。我们将了解它与流量控制的区别,理解网络拥塞的原理,并深入探讨TCP协议中实现拥塞控制的关键算法与机制。


概述 📋

在这一单元中,你已经看到了交通和分组交换如何通过拥塞控制相互交互。

流量控制是关于终点主机的,它确保源主机不会使目的地主机过载。通过发送超过它可以接收的拥塞控制。

另一方面,是关于防止源主机过载链接和路由器之间的。当源主机将太多的包放入网络时,或者当许多源主机将包放入网络时,它们可以填满路由器队列,直到它们溢出。

在TCP中,在发送主机上运行的拥塞控制算法告诉它网络中可以拥有多少包,以便不过度填满路由器队列。TCP总会导致一些包被丢弃,因为这是它使用的反馈信号,以知道路由器队列是否满了。但当它工作良好时,TCP保持包丢弃率低,链接保持良好且充满,并允许流量具有高吞吐量。


网络拥塞的原理 🧠

上一节我们介绍了拥塞控制的基本目标,本节中我们来看看网络拥塞发生的根本原理。

尼克首先解释了网络拥塞的原则。你学习了当一个路由器结构接收的包比它可以发送的包快时发生的事情。如果拥塞是短暂的,那么路由器可以吸收这个额外的流量到一个队列中并排空队列。如果拥塞是长期的,长期到队列溢出,然后路由器必须丢弃一些包。

尼克介绍了一种非常有价值的思考方式:与其想出丢弃包的方案,不如思考你想要网络总体行为的是什么。我们想要网络公*,并解释这意味着在引入最大最小公*性的概念时。最大公*性说网络是公*的,如果你不能增加一个流的速率,而不减少一个速率较低的流的速率。

有许多方法可以实现这个目标,并且今天的网络有许多不同机制。但我们专注于一个。


TCP拥塞控制基础算法 🔢

理解了公*性的目标后,我们来看看TCP为实现这一目标所采用的基础算法。

你学习TCP使用的基本算法,叫做累加增加,乘法减少(AIMD)。当运行顺畅时,TCP增加可以未完成的字节数,它可以在轮询时间内增加一个段大小。当TCP检测到一个包被丢弃时,它减半可以未完成的字节数。

你学习这个行为的样子,使用TCP锯齿图。每个单独的流在共享许多流的链接上都有一个锯齿图。所有这些*均下来,都显示出对链接的持续高使用率。

使用锯齿波形,我们使用符号AIMD来计算TCP吞吐量。如果你假设网络以均匀率 p 丢失包,那么TCP流的吞吐量是:

吞吐量 ≈ (1.22 * MSS) / (RTT * √p)

这个方程做出了许多简化假设,但它实际上通常相当准确。在许多情况下,在考虑网络可能行为的时候,它是一个非常有价值的工具。


TCP拥塞控制的实践实现 ⚙️

理论算法需要具体的机制来实现。接下来,我们将学习TCP如何在实践中实现这些拥塞控制原则。

你已经学习了TCP如何在实践中实现这些原则。菲尔告诉你在20世纪80年代末互联网崩溃的事情,由于拥堵和至今仍在使用的TCP修复措施。

你学习了TCP的三个版本:TCP Tahoe、TCP Reno和TCP New Reno。

我们首先覆盖的重要想法是,TCP端点维护一个拥塞窗口(cwnd)。一个TCP流可能在网络中拥有不被确认的字节数 N,当 N 是其流量控制窗口和拥塞控制窗口的最小值时。你不将比接收端能够处理的包数更多的包放入网络,或比中间链接和路由器能够处理的包数更多。

你学习了TCP如何使用两个状态来控制拥塞控制窗口的大小:慢启动拥塞避免

  • 慢启动让TCP能够快速找到接*正确的拥塞窗口大小。
  • 拥塞避免使用AIMD算法。

TCP从慢启动开始,并在首次检测到丢失时过渡到拥塞避免。

你学习了TCP如何估计其连接的往返时间(RTT),它需要这个估计来确定一个确认超时的时间。通过跟踪*均值,以及接收一个片段所需的时间变异性,TCP也可以避免不必要的重传,并且不会等待太久。

你学习了TCP如何控制它将包放入网络,使用一种叫做自我计时的技术。你在我看给你展示TCP行为的动画时首先看到了自我计时。菲尔,然后带我们通过了一些使用自我计时的例子。TCP只有在网络中有新包时才会放入,当它收到确认时,或者当超时时间到的时候。这在防止拥塞方面非常有用,因为它意味着,TCP只有在数据包已经离开网络时才将数据包放入网络。


TCP的优化机制 🚀

基础的AIMD算法和状态机是核心,但TCP还包含了一些重要的优化来提升性能。

最后,我们覆盖了TCP中添加的三个优化:快速重传、快速恢复和窗口膨胀。

以下是这些优化机制的简要介绍:

  • 快速重传:让TCP在只丢失一个数据包时继续前进,而不是等待超时。TCP重传一个段,当它检测到对前一个段的三个重复确认时。这是TCP继续接收段的迹象,但它没有使用快速恢复接收到这个特定的段。
  • 快速恢复:TCP Reno不退回到慢启动,或三个重复动作,它只是将拥塞窗口减半并留在拥塞避免状态。
  • 窗口膨胀(New Reno优化):使得三个重复动作不导致TCP失去一个RTT值的传输,当它等待缺失的片段被添加时。


总结与展望 🌉

本节课中我们一起学习了计算机网络中至关重要的拥塞控制机制。

现在,交通拥堵最令人着迷的地方是,它是一种被发现的现象。随着互联网的发展,没有人真正想过这样的事情可能会发生,或者如何控制它。它是一种涌现行为,一旦网络变得足够大且被广泛使用。现在,它是网络通信的基本概念,被视为构建强大且性能高的系统至关重要的部分。

TCP的现代版本,比课堂上讨论的稍微先进一些。但主要是它们已经进化到能够处理许多更快的网络。操作系统中发货的TCP版本具有TCP Reno,或在其算法中具有TCP New Reno,以处理非常快的网络,添加了新的功能和操作模式。人们会查看Linux源代码,在那里你会看到这些算法。

但是,这也很酷的是,这些繁琐的算法有一个坚实的概念基础和理论。一方面,我们可以谈论RTT变异估计、快速恢复和自我时钟,另一方面,这些理论支撑着全球互联网的稳定运行。

课程P67:应用与网络地址转换(NAT) 🚀

在本节课中,我们将学习第五单元的核心内容:互联网应用及其运行基础。我们将重点探讨三种关键应用(DNS、HTTP、BitTorrent)以及一个至关重要的网络设备——网络地址转换(NAT)。理解这些内容,是掌握现代互联网如何工作的关键。

概述 📋

互联网的价值和活力,很大程度上源于其上运行的各种应用。本单元将深入探讨驱动互联网的三大基石应用,并首先解析一个使网络得以扩展和安全的关键技术:网络地址转换(NAT)。

网络地址转换(NAT) 🔄

在深入具体应用之前,我们需要先理解网络地址转换(NAT)。你曾在第一单元见过它。NAT设备不仅允许互联网边缘网络规模增长,还允许多个终端设备隐藏在一个公共IP地址之后。

它最初旨在解决两个问题:

  1. 地址复用:使一个内部网络看起来只使用一个公共IP地址。例如,你的家庭Wi-Fi路由器被分配一个公网IP,但可以为家中的手机、电脑等设备分配多个私有IP地址。
  2. 天然安全屏障:由于NAT主要转换从内部网络(边缘)到外部网络(核心)的流量地址,它使得从互联网外部主动发起到内部设备的连接变得困难,从而提供了一种基本的安全特性。

然而,这种设计对许多应用程序产生了重大影响。它使得任何希望与位于NAT后的设备进行通信的应用都变得更加复杂。

因此,如果你今天构建一个互联网应用,就必须处理NAT带来的挑战。理解NAT的工作原理、不同类型及其为何难以应对,至关重要。

本单元将探讨的三大应用 💡

上一节我们介绍了网络的基础设施NAT,本节中我们来看看运行在其上的核心应用。本单元将详细讨论以下三个应用程序:

以下是三大核心应用的简要介绍:

  • 域名系统(DNS):我们之前课程中已有所涉及,本单元将深入研究。DNS使用UDP作为传输协议,是一种简单的客户端-服务器查询交换,用于将域名转换为IP地址等信息。
  • 超文本传输协议(HTTP/万维网):HTTP运行在TCP协议之上。它同样是客户端-服务器模型,我们将查看HTTP请求的构成,以及*年来随着HTTP/2等新版本出现所带来的变化。
  • BitTorrent:这是一个非常有趣的应用,因为它占据了当今互联网流量的相当一部分。BitTorrent使用TCP作为可靠传输,但它并非传统的客户端-服务器模型。它采用点对点(P2P)模型,通过“群组”交换大文件的片段,能以惊人的效率协同管理数据。

总结 🎯

本节课中,我们一起学习了第五单元的框架。我们首先了解了网络地址转换(NAT)如何作为互联网扩展和安全的基础,并认识到它给应用开发带来的挑战。接着,我们概述了本单元将要深入研究的三大互联网基石应用:DNS、HTTP和BitTorrent。希望在本单元结束时,你能掌握这些关键组件,从而真正理解如何构建和运行现代网络应用。

课程 P68:网络地址转换(NAT)简介 🌐

在本节课中,我们将学习网络地址转换(NAT)的基本知识,并解释其工作原理。NAT是现代网络中一个非常普遍且重要的组件,它允许我们解决IP地址短缺问题,并提供一定程度的安全保护。

端到端原则与NAT的引入

上一节我们介绍了网络的基本任务。根据端到端原则,网络的核心任务是尽可能高效、灵活地传输数据包,而所有智能和复杂功能都应放在网络的边缘(即终端主机)。在这个模型中,两个拥有IP地址的主机之间的所有网络设备,其职责仅仅是找到最佳路径并转发数据包。

将智能置于网络边缘的好处在于,这便于添加新功能且不会引入复杂的依赖关系。一旦开始在网络中间(即核心路径上)添加功能,就会引入依赖性和复杂性,使整个系统变得更加普遍和困难。

然而,NAT是一个有趣的例外。它最初在RFC 1631中定义,是一个强有力的例证,说明在网络中间添加某些功能可以带来显著的好处,但同时也引入了新的复杂性。

NAT 的工作原理

上一节我们提到了NAT带来的好处与复杂性,本节中我们来看看NAT具体是如何工作的。

本质上,NAT是一个位于你的设备(如家庭网络)和公共互联网之间的“盒子”。它拥有一个公共互联网IP地址(例如 X)。

以下是NAT处理数据包的基本流程:

  1. 出站数据包(从内部到互联网):当你的电脑(内部地址,例如 I)发送一个数据包到互联网上的服务器(地址 S)时,数据包首先到达NAT。
  2. 地址重写:NAT会重写这个数据包的源地址。它将源地址从你的内部私有地址 I 和端口,改为NAT自己的公共地址 X 和一个由NAT分配的新端口(例如 P_X)。
    • 原始数据包:源: I:Port_I -> 目标: S:Port_S
    • 重写后数据包:源: X:P_X -> 目标: S:Port_S
  3. 状态记录:NAT会在其内部创建一个映射表,记录 (I:Port_I) <-> (X:P_X) 的对应关系。
  4. 入站数据包(从互联网到内部):当互联网上的服务器 S 回复数据包时,它会发送到 X:P_X
  5. 反向翻译:NAT收到这个目标为 X:P_X 的数据包后,查询其映射表,找到对应的内部地址 I:Port_I
  6. 转发:NAT将数据包的目标地址重写为 I:Port_I,并将其转发到你的电脑。

通过这个过程,内部网络的多台设备可以共享一个公共IP地址 X 访问互联网。

NAT 的主要优势

了解了NAT的基本原理后,我们来看看它带来的具体好处。

以下是NAT提供的两大核心优势:

  • IP地址共享:这是NAT最主要的功能。互联网服务提供商(ISP)通常只给家庭或小型企业分配一个或少数几个公共IP地址。通过NAT,内部网络中的多台设备(如手机、电脑、智能家居设备)可以使用私有IP地址(如 10.x.x.x, 192.168.x.x),并通过NAT共享那一个公共IP地址访问互联网。这极大地缓解了IPv4地址耗尽的问题。
    • 公式描述N 台内部设备 -> 1 个公共IP地址 (通过NAT映射)
  • 基础防火墙安全:由于内部设备的真实IP地址被NAT隐藏,互联网上的外部设备无法直接发起连接到这些内部设备。外部连接只能响应由内部设备首先发起的会话。这提供了一种简单的、默认的入站连接过滤,增加了网络的安全性。

NAT 工作实例分析

上一节我们概述了NAT的优势,本节我们通过一个具体场景来深入理解其工作细节。

假设有两个家庭网络,各自通过一个NAT路由器连接互联网。主机A在左侧NAT后,主机B和一台SSH服务器在互联网上。

场景:主机A(10.0.0.111) 连接 SSH服务器(18.1.81.31:22

以下是连接建立过程中数据包地址的变化步骤:

  1. 主机A发起连接:主机A发送TCP SYN包。
    • 源: 10.0.0.111:5000 -> 目标: 18.1.81.31:22
  2. 左侧NAT进行出站翻译:NAT收到包,创建映射 (10.0.0.111:5000) <-> (128.34.22.8:8350),并重写包。
    • 源: 128.34.22.8:8350 -> 目标: 18.1.81.31:22
  3. 服务器回复:SSH服务器向NAT的公共地址回复SYN-ACK包。
    • 源: 18.1.81.31:22 -> 目标: 128.34.22.8:8350
  4. 左侧NAT进行入站翻译:NAT根据映射表,将包目标地址翻译回主机A的地址。
    • 源: 18.1.81.31:22 -> 目标: 10.0.0.111:5000

关键点:NAT必须重写源端口。如果NAT后有两台主机都使用源端口5000,NAT为它们分配相同的外部端口会导致冲突。因此,NAT会为每个会话分配一个唯一的外部端口。

NAT 的状态管理与现实示例

NAT的核心在于维护连接状态。它通常采用一种“按需创建”的策略。

基本模型是:NAT不会预先创建任何映射。只有当它从内部接口收到一个目的地为外部网络的数据包时,才会动态地为这个 (内部IP:端口, 协议) 元组分配一个 (外部IP:端口) 元组,并创建映射记录。随后,利用这个映射来处理返回的数据包。

这种状态管理带来了复杂性,也是NAT会干扰某些网络协议(如P2P应用)的原因。

在现实中,NAT无处不在。例如,当你连接家庭Wi-Fi时,你的设备获得的通常是一个私有IP地址(如 192.168.1.5)。你可以通过以下方式验证:

  • 在电脑上查看本地IP地址(通常是 10.x.x.x192.168.x.x)。
  • 访问一个“显示我的IP”的网站(如 whatismyip.com),你会看到一个不同的公共IP地址。这个公共IP地址就是你家庭路由器的NAT外部地址。

本节课中我们一起学习了网络地址转换(NAT)的基础知识。我们了解到NAT通过重写IP数据包的地址和端口,实现了多台设备共享一个公共IP地址,并提供了基础的安全防护。尽管它违背了严格的端到端原则,并引入了状态管理和协议兼容性等复杂性,但NAT因其解决IP地址短缺问题的巨大实用性,已成为现代互联网不可或缺的组成部分。在后续课程中,我们将探讨NAT的不同类型及其带来的更多挑战。

网络地址转换(NAT)类型详解 🧩

在本节课中,我们将学习网络地址转换(NAT)的不同类型及其工作原理。理解这些类型对于认识NAT如何影响网络通信,以及为何某些应用程序(如在线游戏或P2P应用)在NAT环境下会遇到连接问题至关重要。

概述

NAT的核心功能是将内部私有网络地址转换为外部公共网络地址。虽然这听起来是一个简单的抽象过程,但实际上存在多种实现方式,每种方式在映射创建、数据包过滤和地址分配上都有不同的行为规则。

上一节我们介绍了NAT的基本模型,本节中我们来看看NAT的具体分类和行为差异。

NAT的基本工作模型

NAT的工作模型是:当内部网络节点需要与互联网上的外部节点通信时,NAT设备会在其内部建立一个映射表。这个映射表将内部IP地址和端口号关联到一个外部IP地址和端口号。

例如,当内部主机 10.0.0.101:4512 试图连接外部Web服务器 18.1.1.1:80 时,NAT会重写数据包的源地址。所有来自内部主机的TCP数据包,其源地址都会被改为NAT的外部地址(如 128.34.22.8:6641)。外部服务器看到的数据包就是来自这个地址。当服务器回复时,NAT会再将目的地址翻译回内部主机的地址 10.0.0.101:4512

这个简单的模型引出了两个基本问题:

  1. NAT允许哪些数据包通过其建立的映射?
  2. NAT如何以及何时分配和拆除这些映射?

NAT的主要类型(基于RFC 4787)

根据RFC 4787(原RFC 3489)的定义,NAT主要分为四种类型,它们在数据包过滤的严格程度上有所不同。

以下是四种主要NAT类型的介绍:

1. 全锥型NAT (Full Cone NAT) 🌐

全锥型NAT是限制最少的类型。一旦内部地址 (X:y) 被映射到外部地址 (X‘:y’)任何来自外部互联网的数据包,只要其目的地址是 (X‘:y’),都会被NAT转发给内部主机 (X:y),无论外部数据包的源地址和源端口是什么。

核心行为公式
允许通过映射的数据包 = { 所有目的地址为 (X‘:y’) 的数据包 }

2. 受限锥型NAT (Address-Restricted Cone NAT) 🔒

受限锥型NAT增加了基于源IP地址的过滤。当内部主机 (X:y) 与外部主机 (A:b) 通信并建立映射后,NAT会记录外部主机的IP地址 A。此后,只有源IP地址为 A 的数据包(目的地址为 (X‘:y’))才会被允许通过映射并转发给内部主机。来自其他IP地址的数据包将被丢弃。

核心行为公式
允许通过映射的数据包 = { 目的地址为 (X‘:y’) 且 源IP地址 == A 的数据包 }

3. 端口受限锥型NAT (Port-Restricted Cone NAT) 🔐

端口受限锥型NAT是限制最严格的锥型NAT。它不仅过滤源IP地址,还过滤源端口号。只有当外部数据包的源IP地址和源端口号 (A:b) 与内部主机之前通信过的外部主机地址完全匹配时,数据包才会被允许通过。

核心行为公式
允许通过映射的数据包 = { 目的地址为 (X‘:y’) 且 源地址 == (A:b) 的数据包 }

4. 对称型NAT (Symmetric NAT) 🌀

对称型NAT的行为与前三种有本质区别。它不仅进行端口限制,其关键特性在于:对于同一个内部地址和端口 (X:y),发往不同外部目的地 (A:b) 的数据流,会被分配不同的外部地址端口映射 `(X‘:y’)

这意味着,如果内部主机 10.0.0.101:4512 同时与服务器 S1 (18.1.1.1:3331) 和服务器 S2 (18.1.1.2:3331) 通信,NAT会创建两个独立的映射:

  • 映射1: (10.0.0.101:4512) <-> (128.34.22.8:6641),用于与S1通信。
  • 映射2: (10.0.0.101:4512) <-> (128.34.22.8:9821),用于与S2通信。

对称NAT带来的问题示例
假设一个大型多人在线游戏(MMO)需要玩家在不同服务器间切换。客户端原本通过映射端口 6641 与服务器S1通信。当游戏指示客户端切换到服务器S2时,对称NAT会为这个新连接创建一个全新的外部端口(如 9821)。服务器S2看到客户端来自端口 9821,而系统无法得知这个端口 9821 和之前的端口 6641 属于同一个客户端,从而导致连接断开。这种行为给需要知道客户端固定地址的应用程序带来了巨大挑战。

NAT的复杂行为与边缘案例

除了上述主要类型,NAT设备在实际部署中还有许多复杂行为和需要处理的边缘情况。RFC 4787、5382、5508等文档试图规范NAT的行为。以下是一个典型的边缘案例:

发夹转换 (Hairpinning) 🔄

发夹转换发生在以下场景:两个主机(A和B)位于同一个NAT设备之后。当主机B试图通过NAT的外部映射地址来访问主机A时,就需要发夹转换。

场景

  • 主机A: 10.0.0.101:4512,外部映射为 128.34.22.8:6641
  • 主机B: 10.0.0.99:x
  • B想访问A,发送数据包到 128.34.22.8:6641

问题
如果NAT不做特殊处理,数据包到达NAT后,其目的地址被翻译为 10.0.0.101:4512,但源地址仍是B的内部地址 10.0.0.99:x。当A回复这个数据包时,回复包会直接通过内部交换机发给B,而不会经过NAT。B发送请求时用的是A的外部地址,但收到的回复却来自A的内部地址,这可能导致通信失败。

解决方案(发夹转换)
当NAT收到来自B、目的地址为A外部映射的数据包时,它需要执行两次转换:

  1. 转换目的地址:128.34.22.8:6641 -> 10.0.0.101:4512
  2. 转换源地址:10.0.0.99:x -> 128.34.22.8:y (某个外部端口)
    这样,A看到的请求是来自NAT外部地址 128.34.22.8:y。当A回复时,数据包会发送到NAT,再由NAT转换后发送给B内部的 10.0.0.99:x。这个过程就像数据包在NAT处“绕了一个弯”(发夹弯),因此得名。

总结

本节课中我们一起学习了网络地址转换(NAT)的四种主要类型:全锥型、受限锥型、端口受限锥型和对称型。它们的主要区别在于对通过映射的数据包的过滤严格程度,以及如何为内部连接分配外部映射。我们还探讨了对称型NAT如何给应用程序带来连接性问题,以及NAT需要处理的复杂边缘情况,如发夹转换。理解这些NAT行为差异,是诊断和解决许多现代网络应用连接问题的关键基础。

计算机网络原理 P7:分层原则 🏗️

在本节课中,我们将要学习计算机网络中一个核心的设计原则——分层。我们将探讨分层的定义,通过日常和计算机系统中的例子来理解其工作原理,并分析采用分层设计的诸多优点。


什么是分层?

分层,是指将系统组织成多个分离的功能组件或层的设计方法。这些层按顺序排列和通信。具体而言,每个层只与直接相邻的上层和下层有接口。它为上层提供明确的服务,同时利用下层提供的服务来完成自己的私有处理。

上一节我们介绍了分层的定义,本节中我们来看看分层在现实生活中的例子。

日常生活中的分层示例

分层在我们的生活中无处不在,尤其是在一个服务叠加在另一个服务之上的场景中。

以下是两个常见的例子:

  • 在线订票服务:当你使用谷歌航班、Hipmunk或Kayak等旅行代理网站时,你实际上在使用一个服务层。这个网站为你抽象了各个航空公司网站的细节,让你能通过一个统一的界面查询多家航空公司的票务信息。而航空公司本身,又隐藏了飞机型号、航线规划、餐饮供应商等更底层的细节。
  • 邮政服务:假设你想寄一本书给朋友。你把书放入信封,写好地址,交给邮递员。邮递员将信送到邮局,邮局通过飞机、卡车、火车等多种运输方式将信件送达目的地邮局,最后由当地的邮递员送到你朋友手中。作为寄件人,你无需关心信件具体通过何种交通工具、途经多少个中转站,你只享受“寄出-送达”这个简单的服务。

在这些例子中,每一层都专注于自己的核心任务,并为上一层提供一个清晰、简单的服务接口。这种关注点的分离,正是分层设计的精髓。

计算机系统中的分层

分层原则在计算机系统设计中也被广泛应用。

当我们编写一个计算机程序时,就经历了一个典型的分层处理过程。以下是这个过程的简化步骤:

  1. 编写源代码:程序员使用高级编程语言(如Java、Python)编写代码,这些语言抽象了操作系统和硬件的底层细节。
  2. 编译:编译器作为一个独立的功能组件,接收源代码,进行词法分析、语法解析、优化等一系列处理,最终生成目标代码。其接口是接收源代码,输出目标代码。
  3. 链接:链接器接收编译器生成的目标代码以及所需的库文件,将它们“拼接”在一起,生成最终的可执行文件。
  4. 执行:中央处理器(CPU)执行链接器生成的可执行文件。

分层将“在硬件上运行程序”这个复杂问题,分解为多个模块化、职责明确的步骤。每个组件(如编译器、链接器)都可以独立改进和替换,而无需改动其他层。

分层的优点与边界

采用分层设计主要带来以下五个优点:

  • 模块化与可管理性:将复杂系统分解为更小、更易管理的模块。
  • 明确定义的服务:每一层都为上层提供定义清晰的服务接口。
  • 代码复用:上层可以复用下层已经实现的功能,无需重复造轮子。
  • 关注点分离:每一层可以专注于自己的核心功能,无需了解其他层的具体实现。
  • 持续改进:可以独立地对某一层进行升级、优化或替换,而不会影响整个系统。

此外,对于像互联网这样的通信系统,分层还带来了第六个关键优势:对等通信。通信两端同一层的实体(例如,两台电脑上的网络应用层)可以使用下层提供的服务进行直接“对话”,就像邮件例子中的寄件人和收件人一样。

然而,有时出于性能或实现特定功能的需要,开发者会选择“打破”层与层之间的边界。例如,在C语言中,虽然它旨在隐藏硬件细节,但为了利用某些处理器(如x86-64)的特殊指令或实现操作系统内核,开发者有时不得不直接编写汇编代码。这样做虽然能实现目标,却牺牲了分层带来的灵活性和可移植性——为ARM处理器编写的汇编代码无法在x86-64上运行。

这种“跨层优化”在互联网中也很常见,并带来了一些挑战。例如,网络地址转换(NAT)设备虽然非常有用,但它对网络层和传输层信息的处理,几乎使得在现有互联网上部署新的传输协议变得不可能。这体现了在追求优化与保持系统灵活性之间存在的持续张力。


本节课中我们一起学习了分层原则。我们了解了分层的定义,看到了它在日常生活和计算机系统中的具体体现,并总结了其六大优点:模块化、明确定义的服务、复用性、关注点分离、持续改进和对等通信。同时,我们也认识到,虽然分层是强大的设计工具,但有时出于实际需要,人们也会选择打破层间边界,而这往往会带来灵活性的损失。理解分层原则,是理解现代计算机网络架构的基础。

网络课程 P70:NAT 的影响与应用应对 🧩

在本节课中,我们将探讨网络地址转换(NAT)对现代网络应用产生的具体影响,并了解应用程序为克服这些障碍而采用的各种技术。我们将从NAT如何限制连接建立开始,逐步深入到连接反转、中继、NAT打洞等高级技术,最后讨论NAT对网络协议栈发展的深远影响。


NAT 对连接建立的影响 🔒

上一节我们介绍了NAT的基本工作原理,本节中我们来看看NAT带来的第一个主要影响:限制传入连接。位于NAT后的主机通常无法直接接收来自外部网络的连接请求。

其核心原因在于NAT的映射机制。NAT仅在内部主机主动发起出站连接时,才会在NAT设备上创建临时的 (内部IP:端口, 外部IP:端口) 映射。对于希望从外部接入的服务(如SSH服务器),由于没有预先建立的映射,外部发起的连接数据包无法被正确转发到内部主机。

例如,假设主机A(IP: 10.0.0.1)位于NAT后,并运行着SSH服务(端口22)。当外部主机B试图连接A时,数据包会发送到NAT的公网IP和端口。但由于A并未主动向外发起SSH连接,NAT上没有对应的映射条目,因此这个连接请求会被丢弃。公式化描述为:
外部连接请求 -> NAT (无映射) -> 丢弃

这导致了一个直接后果:位于NAT后的设备难以直接提供公共服务。对于像Skype这样的点对点应用,如果通话双方都在NAT后,则无法直接建立连接。


应对策略:连接反转与中继 🔄

为了解决无法直接建立连接的问题,应用程序发展出了多种应对策略。以下是两种核心方法:

1. 连接反转

当主机A在NAT后,而主机B想连接A时,由于B无法直接发起连接,可以采用“反转”思路。

  • 工作原理:A和B都先与一个双方都能访问的会合服务器建立出站连接。当B想连接A时,它通过会合服务器向A发送一个请求。A收到请求后,主动向B发起一个出站连接。由于NAT允许出站连接,这个连接得以建立。
  • 关键点:连接方向被“反转”了。原本是B连A,实际变成了A连B。

2. 中继转发

如果通信双方都位于NAT之后,连接反转也将失效,因为双方都无法接收对方的入站连接。此时需要引入中继服务器

  • 工作原理:主机A和B分别与具有公网IP的中继服务器R建立连接。A想发送数据给B时,先将数据发给R,再由R转发给B。反之亦然。
  • 影响:这种方式破坏了互联网的端到端原则,引入了额外的中间节点,可能带来延迟、单点故障和隐私顾虑(因此常需配合加密使用)。

高级技术:NAT打洞 🕳️

连接反转和中继都需要第三方服务器持续参与转发,并非真正的点对点直连。NAT打洞技术则旨在帮助两个都在NAT后的主机建立直接的点对点连接

其核心步骤利用了一个事实:某些类型的NAT(如全锥型NAT)在创建映射后,允许任何外部主机使用该映射向内部主机发送数据。

以下是NAT打洞的基本流程:

  1. 地址发现:客户端A和B分别与一个公网服务器S通信。S记录下每个客户端经过NAT转换后的公网IP和端口(即A_NAT, B_NAT)。
  2. 信息交换:服务器S将B的公网地址(B_NAT)告诉A,同时将A的公网地址(A_NAT)告诉B。
  3. 同时发起连接:A和B同时向对方的公网地址(A_NAT, B_NAT)发送UDP数据包。对于全锥型、受限锥型或端口受限锥型NAT,这个向外发送数据包的动作会在各自的NAT上“打”出一个“洞”,即创建或激活一个允许来自对方地址的数据包进入的映射。
  4. 直连建立:一旦“洞”被打通,后续数据包就可以直接在A和B之间传输,无需再经过服务器S。

代码逻辑示意(伪代码):

# 客户端A
my_private_addr = (‘10.0.0.1‘, 6000)
# 1. 联系服务器,获得自己的公网映射地址 A_NAT
a_nat = server.register(my_private_addr)
# 2. 从服务器获取客户端B的公网地址 B_NAT
b_nat = server.get_peer_address(‘B‘)
# 3. 同时向B_NAT发送数据包“打洞”
sendto(‘ping‘, b_nat)
# 4. (等待并接收来自B的数据包,直连建立)

技术限制:NAT打洞对NAT类型敏感。它在全锥型、受限锥型和端口受限锥型NAT上有效,但在对称型NAT上通常会失败。因为对称型NAT为每个不同的外部目的地分配不同的端口映射,导致A与服务器S通信时使用的端口,和A与B通信时使用的端口不同,B无法使用从S获得的地址连接到A。


NAT 对网络协议发展的深远影响 🌉

除了影响具体应用,NAT还对互联网的基础架构产生了深刻的哲学性影响。

1. 传输协议层的“锁定”

NAT设备需要理解并修改传输层协议(如TCP、UDP)的头部信息(如端口号、校验和),才能正确地进行地址转换。这意味着:

  • 现状:如果你发明了一个新的传输层协议(使用新的IP协议号),现有的NAT设备将无法识别和正确处理它,导致数据包被丢弃。
  • 后果:这造成了“先有鸡还是先有蛋”的困境。新协议无法流行,因为无法穿越广泛部署的NAT;而NAT厂商没有动力支持新协议,除非它已经流行。结果就是,互联网被“锁定”在了TCP、UDP和ICMP这几种传输协议上。

2. 互联网“沙漏模型”的变形

传统的互联网被形容为一个“沙漏”,IP层是狭窄的腰部,其下可以承载各种链路技术,其上可以运行各种传输协议。NAT的出现改变了这一模型。

如今,由于NAT的存在,传输层(TCP/UDP)也成为了沙漏腰部的一部分。新的应用若想在全球互联网上工作,几乎必须基于TCP或UDP来构建。这也是为什么现代许多新协议(如QUIC)选择在UDP之上实现,而不是创建全新的传输层协议。

3. 安全与便利的权衡

NAT带来了一些非本意的“安全好处”:它默认屏蔽了所有未被请求的入站连接,为内部网络提供了一道简单的防火墙。这保护了终端用户设备上许多未打补丁的漏洞。然而,这种安全是粗粒度的,并且以牺牲端到端连接能力和增加应用开发复杂性为代价。


总结 📝

本节课中我们一起学习了NAT技术对网络应用产生的多方面影响及应对策略:

  1. 连接限制:NAT默认阻止传入连接,影响了点对点应用的直接通信。
  2. 应对技术:应用程序采用连接反转中继服务器NAT打洞等技术来绕过限制,建立通信。
  3. 协议锁定:NAT导致新的传输层协议难以部署,将互联网应用“锁定”在TCP和UDP之上。
  4. 架构影响:NAT改变了互联网的“沙漏模型”,使传输层成为新的“狭窄腰部”,并引发了关于网络灵活性、安全性与便利性的长期讨论。

尽管NAT破坏了经典的端到端互联网模型,并带来了诸多挑战,但由于其在地址节约和简易安全方面的巨大价值,它已成为现代网络中不可或缺的一部分。理解和适应NAT环境,是开发现代网络应用的必备知识。

课程 P71:NAT 操作详解与行为规范 📡

在本节课中,我们将深入探讨网络地址转换(NAT)设备的核心操作细节,特别是其如何处理数据包以及为确保应用程序正常工作而必须遵循的行为规则和建议。


NAT 映射机制 🔄

上一节我们介绍了NAT的基本概念,本节中我们来看看NAT如何建立和维护地址映射。

NAT设备的核心功能是在其内部接口和外部接口之间建立映射。这个映射将内部网络的IP地址和端口号,转换为外部网络可见的IP地址和端口号。

例如,一个NAT设备的外部IP地址是 128.34.22.8,内部网络有一台主机A,IP地址为 10.0.0.1。当主机A(端口 10001)向外部服务器S(端口 80)发起一个TCP连接时,NAT会创建一个映射。

以下是NAT建立映射的基本过程:

  1. 观察出站包:NAT观察到从内部主机 10.0.0.1:10001 发往外部服务器 S:80 的数据包。
  2. 分配外部地址:NAT为其分配一个外部端口,例如 6641
  3. 建立映射:NAT建立映射 10.0.0.1:10001 -> 128.34.22.8:6641

此后,所有从服务器S返回给 128.34.22.8:6641 的数据包,都会被NAT根据此映射翻译并转发给内部的主机A 10.0.0.1:10001


NAT 对未映射数据包的处理 ❓

那么,如果一个数据包的目的地是NAT的外部地址,但端口没有对应的映射,NAT会如何处理?

NAT本身也是一个IP设备。即使没有设置任何端口映射,它也需要像普通路由器或主机一样响应网络请求。

以下是NAT处理未映射数据包的通用原则:

  • 如果数据包的目的端口在NAT设备本身上运行着服务(例如,家用电器的Web管理界面运行在端口 80),NAT会像普通服务器一样响应。
  • 如果数据包的目的端口没有服务,NAT通常会拒绝连接(例如,发送TCP RST包)或返回ICMP错误。

简而言之,NAT的行为就像一个正常的IP设备,仅在数据包触发已存在的映射或需要创建新映射时,才执行特殊的地址转换操作。


映射的生命周期管理 ⏳

映射不会永久存在。NAT需要管理映射的创建和销毁,以避免耗尽端口资源。

映射的创建通常由内部主机发起的出站数据包触发。而映射的销毁则取决于协议类型:

以下是不同协议的映射超时策略:

  • UDP:由于是无连接协议,没有明确的连接终止信号。NAT会设置一个超时计时器(例如30秒或更长),如果在超时时间内没有该映射下的数据包通过,则删除该映射。
  • TCP:基于连接状态。当NAT观察到TCP连接正常终止(FIN握手)时,可以立即回收映射。如果连接异常中断,也需要依赖超时机制来清理。

RFC文档详细描述了NAT应有的行为,这些规范是基于多年实践经验总结而来,旨在防止NAT干扰应用程序的正常运行。


UDP NAT 行为规范 (RFC 4787) 📜

为了确保UDP应用(如VoIP、在线游戏)能穿透NAT正常工作,IETF在RFC 4787中定义了一系列NAT行为建议。

以下是RFC 4787中的几个核心要求:

  1. 端点无关的映射:NAT为内部主机分配的外部地址/端口映射,应独立于外部目标地址。这意味着它不能是对称型NAT。公式可以理解为:映射(内部IP:端口) = 外部IP:端口,此结果不随 目标IP:端口 改变。
  2. 地址配对保持:如果NAT拥有多个外部IP地址,那么来自同一内部IP地址的所有连接应尽量使用相同的外部IP地址。
  3. 端口映射范围保留:NAT应尽量保持端口号范围。例如,内部端口是知名端口(0-1023),映射的外部端口也应在相同范围;内部是高端口(1024-65535),外部映射也应在高端口范围。

这些要求旨在满足各种UDP应用程序的历史假设和协议期望,避免NAT破坏其功能。


TCP NAT 行为规范 (RFC 5382) 📄

TCP协议由于有连接状态,其NAT行为规范在RFC 5382中定义,它有一些独特于连接建立过程的要求。

以下是RFC 5382中针对TCP的关键要求:

  1. 支持TCP状态机遍历:NAT必须支持所有有效的TCP数据包序列来建立连接,不应限制TCP的实现选项。这对于P2P应用的同时打开连接至关重要。
  2. 端点无关的过滤:与UDP建议类似,在过滤入站数据包时,应采用全锥形NAT的行为,只要数据包的目的地址/端口匹配现有映射,就应允许通过,而不检查源地址。
  3. 处理未请求的SYN包:这是一个重要边缘案例。当NAT收到一个目的地没有映射的入站TCP SYN包(未请求的SYN)时,它不应立即拒绝(如发送RST),而应至少等待6秒。如果在这6秒内,内部主机恰好向该外部地址发起连接(发出SYN),NAT应建立映射并静默丢弃之前收到的那个未请求的SYN包。这个机制是为了支持P2P应用中可能发生的“同时打开”场景。
# 同时打开场景示例
主机A (在NAT A后)             主机B (在NAT B后)
      |                               |
      |-- SYN (to B) --------------->|  # A的SYN到达B的NAT,但无映射,被暂缓处理
      |                               |
      |<------- SYN (to A) ----------|  # B的SYN几乎同时到达A的NAT
      |                               |
# 如果NAT B立即用RST拒绝A的SYN,连接会失败。
# 规范要求NAT B等待,给内部主机B一个发起出站SYN的机会来建立映射。

总结 🎯

本节课中我们一起学习了NAT操作的核心细节。
我们首先了解了NAT如何通过映射表转换内外网地址。
接着,探讨了NAT对无映射数据包的处理方式,以及如何管理UDP和TCP映射的生命周期。
最后,我们详细解读了确保应用程序兼容性的关键行为规范:RFC 4787对UDP NAT的要求(如端点无关映射),以及RFC 5382对TCP NAT的特殊要求(如支持同时打开连接和处理未请求SYN)。
理解这些规范对于开发能在各种NAT环境下稳定运行的网络应用至关重要。

课程 P72:HTTP 协议基础 🕸️

在本节课中,我们将学习超文本传输协议(HTTP)的基本概念、工作原理以及如何分析其性能。HTTP 是现代互联网的基石,最初设计用于传输文档,如今已广泛应用于流媒体、应用程序交互等众多场景。

什么是超文本? 📄

上一节我们介绍了课程概述,本节中我们来看看 HTTP 协议的核心——“超文本”。超文本是一种文档格式,它允许在文档中同时包含格式信息和内容信息。与微软 Word 或 PDF 等二进制格式不同,超文本完全由 ASCII 文本构成,这意味着你可以用任何文本编辑器查看其内容。

以下是一个来自维基百科页面的超文本摘录示例:

<h2>历史</h2>
<p>HTTP 最初旨在传输文档,现在已被用于许多其他事情,如 <a href="http://www.w3.org/pub/WWW/">流媒体</a> 等。</p>
<img src="http://example.com/image.png" alt="示例图片">

在基本层面上,超文本文档就是一个文本文档,浏览器根据文档中特殊的格式命令(称为“标记”)来显示它。例如,<h2> 标签表示这是一个二级标题,应以更大的字体显示。超链接则是一种特殊的标记,表示标签内的内容在被点击时,应加载指定的 URL。

超文本文档的独特之处在于,它可以通过标记引用并嵌入其他文件(如图片),而无需将这些文件的数据直接存储在文档中。

HTTP 的基本模型 🔄

理解了超文本后,我们来看看 HTTP 协议是如何工作的。HTTP 采用客户端-服务器模型,以文档为中心进行通信。

以下是 HTTP 通信的基本流程:

  1. 客户端(如浏览器)向服务器(如 www.stanford.edu)建立一个 TCP 连接。
  2. 客户端通过该连接发送一个 HTTP 请求
  3. 服务器接收并处理请求。
  4. 服务器通过同一个连接发送一个 HTTP 响应 回客户端。
  5. 客户端读取响应,这可能促使它发出更多的请求(例如,获取页面中嵌入的图片)。

HTTP 协议本身也是由 ASCII 文本构成的,人类可读。最常见的请求方法是 GET,用于请求页面。

HTTP 请求与响应的格式 📝

上一节我们介绍了 HTTP 的基本通信模型,本节中我们来详细看看请求和响应的具体格式。

HTTP 请求格式

一个 HTTP 请求由以下几部分组成:

  • 请求行:包含方法(如 GET)、请求的 URL 和 HTTP 版本号。
  • 请求头:零个或多个头部行,每行包含一个头部字段名和对应的值。
  • 空行:用于分隔头部和主体。
  • 请求主体:对于 GET 请求,主体通常为空;对于 POST 等发送数据的请求,主体包含要提交的数据。

以下是 GET 请求的一个示例:

GET /full-duplex/index.html HTTP/1.1
Host: www.stanford.edu
User-Agent: Mozilla/5.0
If-Modified-Since: Wed, 21 Oct 2022 07:28:00 GMT

HTTP 响应格式

一个 HTTP 响应由以下几部分组成:

  • 状态行:包含 HTTP 版本、状态码(如 200)和状态短语(如 OK)。
  • 响应头:零个或多个头部行。
  • 空行:用于分隔头部和主体。
  • 响应主体:请求的实际内容,如 HTML 文档。

以下是成功响应的一个示例:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
Last-Modified: Wed, 21 Oct 2022 07:28:00 GMT

![](https://github.com/OpenDocCN/cs-notes-zh/raw/master/docs/stf-cs144-net/img/7db2f506b048df93c7adb215325dff31_11.png)

![](https://github.com/OpenDocCN/cs-notes-zh/raw/master/docs/stf-cs144-net/img/7db2f506b048df93c7adb215325dff31_13.png)

<!DOCTYPE html>
<html>
...
</html>

使用工具分析 HTTP 🔧

理论需要实践来验证。我们可以使用浏览器开发者工具或 telnet 等命令行工具来观察和分析 HTTP 请求与响应。

以下是使用 telnet 手动发送 HTTP 请求的步骤:

  1. 打开终端或命令提示符。
  2. 输入 telnet www.stanford.edu 80 连接到服务器的 80 端口(HTTP 默认端口)。
  3. 连接成功后,手动输入 HTTP 请求,例如:
    GET /full-duplex/index.html HTTP/1.0
    Host: www.stanford.edu
    
    
  4. 按下两次回车(输入空行)后,你将看到服务器返回的完整 HTTP 响应。

HTTP 性能分析 ⏱️

了解了协议格式后,我们来看看影响 HTTP 性能的因素。早期的 HTTP/1.0 协议非常简单:每个请求都需要建立独立的 TCP 连接,并在响应完成后关闭。

让我们做一个简化的性能分析。假设:

  • 客户端与服务器之间的单向传播延迟为 50ms
  • 一个 HTTP 请求的封装和发送需要 10ms
  • 一个 HTTP 响应的封装和发送需要 20ms
  • TCP 三次握手需要 100ms(SYN 50ms + SYN-ACK 50ms)。

加载一个简单页面(无图片)的总延迟计算如下:

  1. TCP 三次握手:50ms + 50ms = 100ms
  2. 发送请求:10ms(但需等待握手完成后的 ACK,ACK 传输时间假设为 0,因此此步主要受制于传播,可简化为 60ms 从开始到请求发送完毕)
  3. 接收响应:20ms(响应传输)+ 50ms(传播)= 70ms
    总延迟 ≈ 100ms + 60ms + 70ms = 230ms

加载一个包含两张图片的页面(使用两个独立连接)则更慢,因为每个图片都需要重复建立连接、请求、响应的过程,且连接共享同一链路,会产生排队延迟。

总结 📚

本节课中我们一起学习了 HTTP 协议的基础知识。我们首先了解了超文本作为 ASCII 文本格式文档的本质。然后,我们探讨了 HTTP 的客户端-服务器请求-响应模型,并详细剖析了请求和响应的文本格式。我们还介绍了如何使用开发者工具telnet 来实际观察 HTTP 通信。最后,我们通过一个简化的模型分析了 HTTP/1.0 的性能特点,特别是由于为每个资源建立独立连接而带来的延迟问题。理解这些基础知识是学习更高效 HTTP 版本(如 HTTP/1.1 的持久连接、HTTP/2 的多路复用)和现代 Web 性能优化的关键。

课程 P73:HTTP 测验 1 介绍 🧩

在本节课中,我们将要学习一个关于 HTTP 并行请求的测验。这个测验基于我们之前讨论过的“两个并行请求共享同一个链接”的场景。通过分析这个场景,我们可以更好地理解 HTTP 协议在实际应用中的行为。

测验背景介绍

上一节我们介绍了 HTTP 连接的基本概念。本节中我们来看看一个具体的应用场景。

这个测验的背景是:我们有两个并行请求共享同一个 HTTP 链接。这种情况在现代网络应用中非常常见,例如一个网页同时加载多个图片或脚本文件。

测验场景图示

以下是描述该场景的图示:

这张图展示了两个请求(Request A 和 Request B)通过同一个 TCP 连接被发送到服务器。

核心机制分析

在 HTTP/1.1 中,默认启用了持久连接(Persistent Connection)。这意味着一个 TCP 连接可以用于多个请求和响应,而不是每个请求完成后就关闭。这提高了效率,但也引入了新的问题,即如何管理多个并行的请求。

当两个请求共享一个连接时,它们必须被序列化。也就是说,请求和响应必须按顺序发送和接收。这可以用一个简单的模型来描述:

客户端 -> 服务器: 发送请求A
客户端 -> 服务器: 发送请求B
服务器 -> 客户端: 发送响应A
服务器 -> 客户端: 发送响应B

然而,实际的网络行为可能更复杂,因为请求和响应的处理时间不同。

可能遇到的问题

以下是并行请求共享连接时可能遇到的关键问题:

  1. 队头阻塞:如果请求A的响应处理得很慢,即使请求B的响应已经准备好,它也必须等待请求A的响应完全发送完毕后才能开始传输。
  2. 响应顺序:服务器响应的顺序是否一定与客户端发送请求的顺序一致?这是一个需要思考的问题。
  3. 资源竞争:两个请求是否可能相互影响,例如竞争连接带宽?

后续图示提示

为了帮助分析,测验还提供了更多的视觉线索:

这些图示可能展示了请求与响应在时间线上的具体交互过程,或者揭示了某种特定的现象(如队头阻塞)。仔细观察时间线、箭头方向和标签是解答测验的关键。

总结

本节课中我们一起学习了 HTTP 测验 1 的背景。我们回顾了两个并行请求共享一个 HTTP 连接的基本场景,并分析了其中可能涉及的队头阻塞、响应顺序等核心概念。理解这些底层机制对于诊断网络性能问题和深入学习 HTTP/2、HTTP/3 的改进至关重要。接下来的测验将基于这些图示,挑战你对HTTP交互顺序和结果的理解。

课程P74:HTTP Quiz 1 答案解析 📚

在本节课中,我们将详细解析一道关于HTTP请求与响应时间计算的题目。我们将通过分析网络传输的各个阶段,理解总延迟是如何构成的。


题目总览与答案

题目的答案是一百五十毫秒。根据题目提供的图示,整个过程总共需要二百五十毫秒

网络传输路径分析

上一节我们得到了总时间,本节中我们来分解这个时间是如何构成的。

图示中的蓝色线条代表了数据从客户端到服务器的传输路径。

红色线条则代表了数据从服务器返回客户端的传输路径。其中,链路交换(例如TCP握手)本身需要一百毫秒

第一个请求与响应

以下是第一个请求的详细时间线:

  • 0ms: 客户端发出第一个请求。
  • 60ms: 第一个请求经过60毫秒的传播延迟后到达服务器。此时,服务器可以开始准备发送响应。
  • 160ms: 在请求到达100毫秒后(即第160毫秒),服务器开始发送响应的第一部分。题目提示,服务器会为第一个响应部分发送两个数据包。

第二个请求与并行处理

当服务器正在处理第一个响应时,客户端发送了第二个请求。

以下是第二个请求到达后的处理过程:

  • 服务器在收到第二个请求时,会为另外两个响应部分发送数据包。
  • 这意味着从服务器发出响应到客户端完全接收,总共还需要九十毫秒的传输时间。

队列延迟与总时间计算

一个关键点是队列延迟的掩盖

在第一个请求到达服务器后,第二个请求所产生的额外“打包”或处理延迟,被响应的发送队列掩盖了。也就是说,服务器在处理第一个响应的同时,也在准备第二个请求的响应,没有造成额外的空闲等待。

因此,结合所有阶段,完成整个交互过程总共需要四百八十毫秒

初始请求响应时间

特别地,对于HTTP页面的初始请求-响应周期(即获取第一个资源),所需的时间是二百三十毫秒


课程总结

本节课中,我们一起学习了如何分析一个简单的HTTP请求-响应场景的时间线。我们分解了传播延迟、链路交换时间以及服务器并行处理请求如何影响总完成时间,并理解了队列机制如何优化整体性能。核心在于区分不同方向的传输路径,并计算它们之间的重叠与顺序关系。

课程P75:HTTP测验2解析 🧩

在本节课中,我们将一起分析一个关于HTTP页面加载时间的测验。我们将学习如何根据给定的网络参数,计算在特定情况下加载一个网页所需的总时间。我们会逐步拆解问题,并应用核心的网络延迟公式。

概述

本次测验基于一个具体的网络场景:客户端通过HTTP协议请求一个包含1个HTML文件和3张图片的网页。我们已知网络往返时间(RTT)、链接带宽以及文件大小。目标是计算在“情况二”(即非持久HTTP连接且无并行TCP连接)下,加载整个页面所需的时间。

上一节我们介绍了HTTP的基本模型,本节中我们来看看如何将理论应用于具体计算。

场景与参数

以下是题目中给出的所有已知条件:

  • 往返时间 (RTT): 4
  • 链接带宽: 2 Mbps (即 2 * 10^6 比特每秒)
  • HTML文件大小: 100 字节
  • 每张图片大小: 100 字节
  • 连接模型: 非持久HTTP,且每次只建立一个TCP连接(无并行)。

核心计算原理

要计算总时间,我们需要理解两个核心组成部分:建立连接的时间开销传输数据的时间

  1. TCP连接建立: 在非持久HTTP下,每次传输文件前都需要经历一次“三次握手”来建立TCP连接。这个过程需要 1个RTT 的时间。
  2. 文件传输时间: 文件传输时间由文件大小和链路带宽决定。其计算公式为:
    传输时间 = 文件大小 / 带宽
    我们需要确保单位一致(通常将字节转换为比特,1字节 = 8比特)。

分步加载过程分析

现在,我们根据“情况二”的规则,一步步模拟加载页面的过程。

整个过程是串行的,即必须等上一个文件完全请求并传输完毕后,才能开始下一个文件的请求。

第一步:获取HTML文件

  1. 客户端发起TCP连接(1个RTT)。
  2. 连接建立后,客户端发送HTTP请求,服务器响应并传回HTML文件。请求和响应时间合计为1个RTT,文件传输也需要时间。
    因此,获取基础HTML文件的总时间为:1 RTT (握手) + 1 RTT (请求/响应) + HTML文件传输时间

第二步:获取第一张图片
HTML文件加载后,客户端解析发现需要图片,于是开始为第一张图片建立新的TCP连接。过程与第一步完全类似。
获取每张图片的时间均为:1 RTT (握手) + 1 RTT (请求/响应) + 图片传输时间

第三步:获取剩余图片
由于没有并行连接,获取第二、第三张图片的过程与第二步完全相同,且必须依次进行。

以下是各阶段时间的具体计算:

  • 计算传输时间
    带宽 = 2 Mbps = 2 * 10^6 bps。
    文件大小(以比特计) = 100 字节 * 8 = 800 比特。
    单个文件传输时间 = 800 bits / (2 * 10^6 bits/sec) = 0.0004 sec。这个值远小于1个RTT(4秒),因此在计算中通常可以忽略不计。

  • 计算总时间

    1. 获取HTML: 1 RTT (握手) + 1 RTT (请求/响应) = 2 RTT
    2. 获取图片1: 1 RTT (握手) + 1 RTT (请求/响应) = 2 RTT
    3. 获取图片2: 2 RTT
    4. 获取图片3: 2 RTT
      总RTT数量 = 2 + 2 + 2 + 2 = 8 RTT
      总时间 = 8 * 4 sec = 32 sec

关键点总结

本节课中我们一起学习了如何计算非持久HTTP连接且无并行时的页面加载时间。关键在于理解每个独立文件的获取都需要经历完整的TCP连接建立过程(消耗1 RTT)和请求-响应周期(消耗1 RTT)。当传输时间远小于RTT时,总时间主要由这些网络延迟的累加决定。在本例中,加载一个包含4个小资源的页面总共需要 32秒

📘 课程 P76:HTTP 测验 2 解析

在本节课中,我们将详细解析一个关于 HTTP 并行请求与延迟计算的测验。我们将通过具体的案例和图表,理解网络延迟如何影响资源加载时间,以及并行请求如何优化整体性能。


📊 案例一:单次请求耗时分析

上一节我们介绍了课程背景,本节中我们来看看第一个案例的计算。

案例一的答案是九十五毫秒,其网络设置是二十毫秒的传播延迟。

以下是计算过程:

  • 客户端发送请求到服务器需要 25毫秒(包含传播与处理时间)。
  • 服务器返回响应到客户端需要 30毫秒
  • 加上初始的页面加载时间,总耗时是九十五毫秒

这个计算可以用一个简单的公式表示:
总耗时 = 初始页面加载时间 + 请求时间 + 响应时间


🔄 案例二:并行请求耗时分析

理解了单次请求后,我们来看看更复杂的并行请求场景。

案例二的答案是三百八十毫秒。加载初始页面需要九十五毫秒。随后,图像开始并行加载。

以下是加载过程的分解:

  1. 初始页面加载完成(95ms)时,客户端立即请求图像一和图像二。
  2. 图像一加载完成(95ms)时,图像三开始请求,与此同时图像二已在传输中。
  3. 图像三完成(95ms)时,图像四开始请求,图像二此时已完成。
  4. 最后,加载图像五需要另一个九十五毫秒。

因此,总耗时为:95ms + 95ms + 95ms + 95ms = 380ms


📈 图解并行请求流程

为了更直观地理解,让我们通过图表来分析并行请求的时序。

这个图表从初始页面请求后开始,展示了客户端请求多张图像时发生的情况。我们从九十五毫秒的时间点开始观察。

以下是图表中的关键事件序列:

  • 135ms: 客户端发送请求一。
  • 140ms: 客户端发送请求二。
  • 165ms: 请求一到达服务器(包含20ms延迟和5ms排队延迟)。
  • 服务器开始发送响应。当请求二到达时,其响应数据段在请求一的响应段之后排队等待发送。
  • 190ms: 请求一的响应段B到达客户端。

⚙️ 连接管理与请求轮次

当第一个请求的响应到达后,客户端立即开启新连接请求第三张图像。

这里有一个重要概念:因为第二个请求是并行处理的,客户端无需等待它完成即可开始第三个请求

请求会按此模式持续进行:

  • 第三个请求完成后,立即开始第五个请求。
  • 每个这样的“轮次”大约需要九十五毫秒。
  • 如果有六张图像,最后一个轮次将需要额外时间,总时间会延长。

💡 核心机制与性能启示

仔细观察图表,直到你理解其运作机制。

核心机制在于:请求和响应在队列中的延迟导致了它们被自然间隔开,这反而减少了整体的队列拥堵延迟

这带来了一个关键性能优势:因为多个操作并行进行,它们可以掩盖彼此的延迟。如果你仔细思考这些数字:

你会发现:并行请求多个资源,并不比顺序请求单个资源花费显著更长的时间

虽然存在额外的数据包处理延迟,但在现代网络中,这部分时间占比很小。单个请求无法充分利用网络带宽,而多个并行请求则可能做到。


🎯 课程总结

本节课中我们一起学习了 HTTP 并行请求的延迟计算模型。

我们通过两个案例,分析了单次请求与并行请求的总耗时,并借助图表理解了请求与响应在队列中的调度机制。最关键的是,我们明白了并行请求如何通过掩盖延迟来提升效率,并且了解到在 HTTP/1.x 中,每个连接只能处理一个未完成请求的限制,这凸显了建立多个连接或使用 HTTP/2 等多路复用技术的重要性。

希望本教程能帮助你清晰地理解网络延迟对网页加载的影响。

课程 P77:HTTP/1.1 持久连接详解 🚀

在本节课中,我们将要学习 HTTP/1.1 协议中一项非常重要的优化技术——持久连接(Keep-alive)。我们将了解它如何解决 HTTP/1.0 的效率问题,并通过对比分析其性能提升。


HTTP/1.0 的局限性

上一节我们介绍了 HTTP 协议的基本请求-响应模型。本节中我们来看看 HTTP/1.0 的工作方式及其效率瓶颈。

HTTP 是一种基本的请求-响应协议。在 HTTP/1.0 中,客户端为了请求一个文档,需要打开一个 TCP 连接。它发送一个 GET 请求,服务器响应状态码(例如 200 OK)并在响应体中包含文档内容,随后连接立即关闭。

如果客户端需要请求第二个文档(例如网页中的图片),就必须打开第二个全新的连接。在早期网页内容以文本为主、仅包含少量图片时,这种方法尚可接受。

以下是 HTTP/1.0 简单请求的示意代码:

GET /index.html HTTP/1.0
Host: www.example.com

然而,根据我们对 HTTP/1.0 的性能分析,使用特定网络参数加载一个包含文本和两张图片的页面需要超过 500 毫秒。其中,大量时间被消耗在反复建立和关闭 TCP 连接上。此外,每个新连接的 TCP 拥塞窗口都处于初始状态,没有机会增长,无法充分利用网络带宽。

因此,HTTP/1.0 的方法可能非常浪费资源。客户端花费大量时间建立连接,且 TCP 性能无法得到优化。


HTTP/1.1 的解决方案:持久连接

为了解决上述问题,HTTP/1.1 引入了持久连接机制。它通过在请求和响应报文中添加特定的头部字段来实现。

一个 HTTP/1.1 的请求可以包含一个 Connection 头部。例如:

GET /index.html HTTP/1.1
Host: www.example.com
Connection: keep-alive

这个头部用于提示服务器,客户端希望在本次响应结束后保持连接打开,以便发送后续请求。服务器可以根据自身情况决定是否遵从该提示。

相应地,服务器的响应中也会包含 Connection 头部,告知客户端其最终决定。如果服务器同意保持连接,它还会通过 Keep-Alive 头部(注意拼写)告知连接将保持多久。例如:

HTTP/1.1 200 OK
Content-Type: text/html
Connection: keep-alive
Keep-Alive: timeout=5, max=100

此后,客户端可以在同一连接上连续发送更多请求,而无需重新建立连接。当然,客户端仍然可以打开多个并行连接。


性能对比分析

让我们通过一个更现实的场景来对比 HTTP/1.0 和 HTTP/1.1 的性能。假设一个页面包含 11 张图片,网络延迟较低。

以下是性能计算的核心公式:
总时间 ≈ 建立连接时间 + (请求数量 × 单次请求-响应延迟)

  • 对于 HTTP/1.0:每个资源都需要独立连接。加载主页面和11张图片需要多轮请求。计算表明,总时间可能达到 1421 毫秒
  • 对于 HTTP/1.1:利用持久连接,所有请求可以在一个连接内连续发送。计算表明,总时间仅需 326 毫秒

因此,在本例中,HTTP/1.1 比 HTTP/1.0 快了 4 倍以上。性能提升主要源于避免了重复建立连接的开销,并允许 TCP 拥塞窗口增长,从而提高了数据传输效率。


后续发展:SPDY 与 HTTP/2

HTTP/1.1 自1997年左右沿用至今。*年来,为了进一步提升性能,出现了新的协议。

谷歌开发的 SPDY 协议对 HTTP 做了多项改进:

  1. 请求管道化:允许同时发送多个请求,无需等待响应。
  2. 头部压缩:消除了 HTTP/1.1 中大量重复的头部信息,减少了数据传输量。
  3. 服务器推送:服务器可以预测客户端需求,主动推送资源。

SPDY 协议的成功实践最终成为了 HTTP/2 标准的基础。HTTP/2 解决了 HTTP/1.1 中队头阻塞等问题,并广泛采用了头部压缩等特性,能够为现代复杂网页带来显著的速度提升,目前已被大多数网站所采用。


总结

本节课中我们一起学习了:

  1. HTTP/1.0 的局限性:每个资源请求都需要独立的 TCP 连接,导致延迟高、效率低。
  2. HTTP/1.1 的持久连接:通过 Connection: keep-alive 头部,允许多个请求-响应在同一个 TCP 连接上顺序进行,大幅减少了连接建立开销,提升了性能。
  3. 性能对比:通过理论计算,展示了在典型场景下 HTTP/1.1 相较于 HTTP/1.0 的巨大速度优势。
  4. 技术演进:了解了从 HTTP/1.1 到 SPDY,再到现代 HTTP/2 协议的发展脉络,它们致力于解决更复杂的网络性能问题。

持久连接是 Web 性能优化中的一个基础且关键的机制,理解它有助于我们更好地认识现代网络应用的工作原理。

课程 P78:BitTorrent 协议详解 🧩

在本节课中,我们将要学习 BitTorrent 协议。这是一种用于高效分发大型文件的点对点(P2P)网络协议。我们将了解其核心工作原理、文件分片机制、节点发现方式以及用于激励共享的算法。


协议概述与基本原理 🌐

BitTorrent 是一种高效的互联网应用,它允许用户分享和交换大型文件。其核心思想是,一个客户端可以从多个其他客户端并行地请求文件的不同部分。

它将文件分解为称为“片段”的数据块。当一个客户端从另一个客户端下载一个片段后,它会告知其他客户端自己已拥有该片段。这种协作下载文件的客户端集合被称为“蜂群”。


加入与发现蜂群 🐝

上一节我们介绍了蜂群的概念,本节中我们来看看客户端如何加入一个蜂群。

一个客户端通过下载一个包含文件信息的 .torrent 文件来加入蜂群。

这个文件包含了文件大小、片段大小以及如何联系其他客户端等信息。

早期,.torrent 文件会指定一个“追踪器”。这是一台负责追踪蜂群中有哪些客户端的服务器。当客户端加入时,它会向追踪器请求一个其他客户端的列表,然后通过 TCP 与这些客户端建立连接。一个 BitTorrent 客户端可以同时打开大约一百个 TCP 连接。

在 2000 年代后期,追踪器开始受到过多关注。目前,大多数客户端已过渡到使用“分布式哈希表”。

DHT 是一种将哈希值映射到节点的方法。支持 DHT 的节点集合可以频繁变化,但你仍然可以找到节点。因此,映射关系实际上分布在所有参与节点上,而不是依赖于一个中央查找表。这是一种让节点协作存储数据(例如,存储蜂群成员列表)的方式。


文件分片与完整性校验 🔍

了解了如何加入网络后,我们来看看 BitTorrent 如何处理文件本身。

BitTorrent 将文件分成 N 个片段,每个片段通常是 256 KB 或更大。

文件大小 / 片段大小 = 片段数量 (N)

这个尺寸是为了确保每个 TCP 传输流的持续时间足够长,使其拥塞窗口能够增长到一个合理的大小,从而支持高吞吐量。

此外,BitTorrent 还将片段进一步划分为“子片段”。这样它可以从多个对等节点并行请求一个片段的不同部分,从而减少延迟。

片段也是 BitTorrent 用于检查数据完整性的基本单位。一个 .torrent 文件包含了每个片段的 SHA-1 哈希值。SHA-1 是一种加密哈希函数,具有一个关键属性:给定一个哈希值 H,很难构造出另一个具有相同哈希值 H 的数据块。

这意味着,如果 .torrent 文件声明片段 5 的哈希是 H,那么客户端下载后计算哈希,若结果不是 H,则说明数据损坏或被篡改,客户端会丢弃该片段并重新下载。

这种机制曾引发一个有趣的事件。2006年,HBO 的新剧《罗马》有多个热门种子,但许多用户无法下载。调查发现,网络中存在大量提供错误片段的恶意节点,导致客户端陷入不断下载和验证失败的循环。这被认为是版权方的一种干扰手段。

现在,客户端可以将提供大量错误片段的节点加入黑名单。


片段选择策略:最稀有优先 ⚖️

当客户端连接后,它们会定期交换各自拥有的片段信息。客户端会优先尝试从其邻居节点下载“最稀有”的片段。

这样做的原因是:如果某个片段在整个蜂群中只有极少数节点拥有,那么这些节点就会成为下载瓶颈。一旦这些节点离线,该片段就可能永久丢失,导致整个文件无法被完整下载。“最稀有优先”策略有助于*衡每个片段的可用性。

此策略的一个例外发生在下载接*完成时。当客户端只剩下最后几个片段时,它会同时从多个节点请求这些片段。这是为了防止向一个速度很慢的节点请求最后一片而陷入长时间等待。虽然这可能导致下载一些重复的子片段,浪费少量带宽,但由于整个文件通常包含数千个片段,这个成本很小,是值得的。


上传激励算法:以牙还牙 🤝

客户端从对等节点请求片段,但如果你向每个节点都上传数据,你会有很多条低速的 TCP 流。BitTorrent 的目标是维持较少但更快的连接。

其核心思想是:你优先向那些给你发送数据的节点上传数据。这创造了一个共享的激励。该算法通过“阻塞”大多数节点来实现。

以下是算法的步骤:

  1. 客户端测量从每个邻居节点下载的速度。
  2. 选择其中速度最快的 P 个节点。P 通常是一个小数字,例如 4,或者是邻居总数的*方根。
  3. 客户端只向这 P 个节点上传数据,而“阻塞”其他节点,不向他们发送数据。

这个算法被称为“以牙还牙”。


算法优化与随机探索 🔄

“以牙还牙”算法的一个问题是探索不足。网络中可能有一个非常好的节点,能够以极快的速度向你发送数据,但前提是你先开始向它上传一些数据。

为了解决这个问题,BitTorrent 大约每 30 秒会随机解除对一个被“阻塞”节点的限制。这个节点因此有机会进入速度最快的 P 个节点列表。


对算法的博弈:BitTyrant ⚔️

“以牙还牙”算法相当健壮,但它并非完美。2007年的一篇论文提出了一个名为 BitTyrant 的自私客户端策略,可以“游戏”系统。

基本观察是:在标准 BitTorrent 中,一个节点会将其上传带宽*均分配给其未阻塞的 P 个节点。因此,每个节点获得 1/P 的上传带宽。但关键在于,只要你进入了某个节点的前 P 名,你就能获得其全部上传带宽。

BitTyrant 的策略是:它精确计算并向每个邻居节点上传“刚好足够”的数据,以进入该邻居的“前 P 名”列表,而不会浪费更多上传带宽。然后,它用节省下来的带宽去“贿赂”其他节点,试图进入更多节点的“前 P 名”列表。

这样做的目的是最大化那些“不阻塞你”的节点数量,从而最大化自己的下载速度。实验表明,使用 BitTyrant 可以将吞吐量提高约 70%。

研究还发现,如果每个人都使用 BitTyrant,整体性能会有小幅提升,但收益最大的是当只有你一个人使用它时。

相关论文链接:The BitTyrant: Strategic Behavior in BitTorrent


总结 📚

本节课中我们一起学习了 BitTorrent 协议的核心机制。我们来总结一下整个流程:

  1. 启动:客户端下载一个 .torrent 文件(通常通过 HTTP),该文件描述了要下载的文件以及如何找到其他节点(通过追踪器或 DHT)。
  2. 分片:文件被分成多个片段。
  3. 交换:客户端通过 TCP 连接与其他节点(对等方)通信,交换各自拥有的片段信息。
  4. 选择:客户端采用“最稀有优先”策略选择要下载的片段,以*衡网络中的资源。
  5. 激励:客户端使用“以牙还牙”算法,只向下载速度最快的 P 个节点上传数据,并定期随机探索新节点,以激励共享并优化连接。

通过这些巧妙的机制,BitTorrent 实现了高效、去中心化的大文件分发。

课程 P79:DNS 基础(第1部分)🌐

在本节课中,我们将要学习域名系统(DNS)的基础知识。DNS是互联网的核心服务之一,负责将人类可读的域名(如 www.example.com)转换为计算机可识别的IP地址(如 192.0.2.1)。我们将从DNS的起源讲起,了解其设计目标、核心架构以及查询的基本工作原理。


从URL到IP地址的映射问题 🔗

让我们先观察一个典型的URL。一个基本的URL,就像你在浏览器地址栏中输入的那样,通常由三部分组成:

  1. 应用协议:例如 http://,它指定了请求文件所使用的协议,并默认对应TCP的80端口。
  2. 主机名:例如 cs144.stanford.edu,这是一个由点分隔、人类可读的名称,用于指定我们想要联系的实际网络节点。
  3. 文件路径:例如 /index.html,它指定了在应用层(如HTTP)上我们想要请求的具体资源。

到目前为止,我们讨论互联网时一直使用IP地址。但当我们输入URL时,使用的是主机名。这就引出了一个核心问题:我们如何将人类可读的主机名翻译成IP地址?

当然,你可以直接在URL中输入IP地址来替代主机名。但人类可读的名称非常有用,因此从互联网诞生之初,人们就意识到了其重要性。


早期方案:主机文件(hosts.txt)📜

在互联网还很小的早期,有一个名为 hosts.txt 的中央文件。互联网上的每一台主机及其对应的IP地址都记录在这个文件中,由网络信息中心(NIC)维护。

工作原理

  • 每个联网节点会定期联系位于 sri-nic.arpa 的中央服务器。
  • 使用文件传输协议(FTP)下载 hosts.txt 文件的最新版本。
  • 新版本包含了所有新增的主机,节点从而能将主机名映射到IP地址。

局限性
对于只有少数主机的情况,这种方法尚可。但随着互联网规模(节点数 n)的增长,其扩展性问题变得突出。每个节点都需要定期下载一个长度与 n 成正比的文件,所需的网络容量呈 增长。这显然不是一个可扩展的长期解决方案。


DNS的诞生与设计目标 🎯

域名系统(DNS)的诞生,正是为了解决上述扩展性问题。其基本任务是:将人类可读的名称映射到地址(最初是IP地址,现在可以映射到更多类型的值)

DNS的设计考虑了以下几个关键因素:

  1. 处理海量记录:理论上需要能处理数十亿级别的映射记录。
  2. 分布式控制:不应由一个中心机构管理所有名称。例如,斯坦福大学可以管理 stanford.edu 下的名称,而亚马逊可以管理 amazon.com 下的名称。
  3. 鲁棒性(Robustness):系统不应因单个节点的故障而整体崩溃。

使这个分布式、层次化且鲁棒的系统成为可能,主要依赖于两个关键特性:

  • 以读为主的数据库:名称到地址的映射被读取的频率远高于被更新的频率。主机名和IP地址的绑定关系相对稳定。
  • 宽松的一致性:允许映射变更的传播存在一定延迟。即,并非所有用户都需要立即看到最新的变化。

这两个特性共同允许DNS进行广泛的缓存。一旦某个查询结果被获得,就可以在本地缓存一段时间,并用于回答后续相同的查询,从而极大地减轻了根服务器的压力并提高了响应速度。


DNS的层次化命名架构 🏛️

为了实现分布式管理,DNS采用了层次化的命名结构。我们都对此很熟悉:

  • 根域(Root):位于最顶层,用一个点 . 表示,对应根域名服务器。
  • 顶级域(TLD):位于根域之下,例如 .com.org.edu.cn(国家代码顶级域)。
  • 二级域(SLD):在顶级域之下,例如 stanford.edubaidu.com
  • 子域(Subdomain):域的所有者可以进一步创建子域,例如 cs.stanford.edu(斯坦福大学下的计算机科学系),www.google.com(谷歌公司下的万维网服务)。

关键机制

  • 区域(Zone)与授权:每个层次(根、TLD、域名、子域名)都可以作为一个独立的“区域”进行管理。上级区域可以将子区域的管理权授权给下级。例如,根服务器将 .edu 区域的管理权授权给 .edu 的服务器;.edu 服务器又将 stanford.edu 区域的管理权授权给斯坦福大学的DNS服务器。
  • 服务器复制:每个区域都可以由多台复制的服务器提供服务,而非单点。这提供了高可用性和鲁棒性。即使一台服务器宕机,其他副本仍能应答查询。

根服务器与查询流程 🔍

根服务器

  • 根区域由标记为 A 到 M 的13组根服务器提供服务。
  • 这些服务器通过 任播(Anycast) 技术被高度复制。这意味着全球有数百台物理服务器共享这13个IP地址。你的查询会自动被路由到离你最*的一台根服务器实例。
  • 这种设计使得根服务器极其鲁棒,能够抵御大规模分布式拒绝服务(DDoS)攻击。

DNS查询示例
假设一个客户端想知道 www.stanford.edu 的IP地址。

以下是查询步骤:

  1. 客户端 -> 本地解析器(递归查询):客户端向其配置的本地DNS解析器(通常由ISP或网络管理员提供)发送一个递归查询:“请告诉我 www.stanford.edu 的IP地址”。
  2. 解析器 -> 根服务器(非递归查询):假设解析器的缓存是空的。它首先向一个根服务器发送非递归查询:“请问,负责 .edu 域的服务器是谁?”
  3. 根服务器 -> 解析器:根服务器回复:“负责 .edu 的服务器是这些(提供 .edu TLD服务器的IP地址列表)”。解析器缓存此结果。
  4. 解析器 -> .edu TLD服务器(非递归查询):解析器接着向 .edu 服务器发送非递归查询:“请问,负责 stanford.edu 域的服务器是谁?”
  5. .edu TLD服务器 -> 解析器.edu 服务器回复:“负责 stanford.edu 的服务器是这些(提供斯坦福大学DNS服务器的IP地址列表)”。解析器缓存此结果。
  6. 解析器 -> stanford.edu 权威服务器(非递归查询):解析器最后向斯坦福大学的权威DNS服务器发送查询:“请问,www.stanford.edu 的IP地址是什么?”
  7. stanford.edu 权威服务器 -> 解析器:斯坦福大学的服务器回复:“www.stanford.edu 的IP地址是 X.X.X.X”。解析器缓存此最终结果。
  8. 解析器 -> 客户端:解析器将最终的IP地址 X.X.X.X 返回给客户端。

缓存的作用
如果几分钟后,另一个客户端也查询 www.stanford.edu,本地解析器就可以直接从缓存中返回答案,无需再次进行这一长串查询。这极大地提升了效率。

安全提示
这种缓存机制也带来了安全风险,例如 DNS缓存投毒(Cache Poisoning)。攻击者可能试图向解析器注入伪造的记录,使其将 www.stanford.edu 解析到恶意IP地址。我们将在后续课程的安全部分讨论这种攻击及其防御。


总结 📝

本节课中我们一起学习了DNS的基础知识:

  1. DNS的目的:解决将人类可读的域名映射到机器IP地址的核心问题。
  2. 历史演进:从中心化的 hosts.txt 文件发展到分布式、可扩展的DNS系统。
  3. 设计核心:基于层次化命名区域授权实现分布式管理;利用以读为主宽松一致性的特性支持广泛缓存,以实现高性能和高鲁棒性。
  4. 架构组成:包括根服务器、TLD服务器、权威域名服务器和本地解析器构成的层次结构。
  5. 查询流程:理解了递归查询与非递归查询的区别,以及一个DNS查询从客户端到获取IP地址的完整迭代过程。

DNS是互联网的无声基石,它让我们能够通过简单的名字访问复杂的网络世界。在下一节课中,我们将深入探讨DNS的记录类型和报文格式。

计算机网络原理 P8:封装原理 🔄

在本节课中,我们将要学习计算机网络中的一个核心架构原理——封装。封装是分层和分组交换思想结合的产物,它定义了数据如何在网络中被打包和传输。

概述 📋

封装是组织分组内信息的原则,它允许我们维护分层的独立性,同时让不同层的数据共享同一个分组。简单来说,封装就是将数据像“俄罗斯套娃”一样,一层一层地包装起来进行发送。

什么是封装? 🧩

上一节我们介绍了分层模型,本节中我们来看看分层思想在数据包中的具体体现——封装。

当您发送数据时,例如一个TCP分段,它并不会单独在网络中旅行。这个TCP分段会被放入一个IP分组中,而IP分组又会被放入一个链路层帧(如以太网帧)中。这个过程就是封装。

封装 就是将高层协议的数据单元,作为低层协议数据单元的负载(Payload)进行打包的过程。其核心关系可以表示为:
高层数据单元 -> 成为 -> 低层数据单元的负载

分层与封装的协作 🤝

分层将复杂系统分解为独立的模块,而封装是实现分层协作的物理机制。

  • 分层的好处:每层提供特定的服务,并对上层隐藏实现细节。只要接口不变,上层无需关心下层的具体变化。
  • 封装的角色:封装使得这种“隐藏”成为可能。每一层只处理自己头部/尾部的信息,并将内层传来的整个数据包视为自己的负载。

这种设计带来了巨大的灵活性:

  • 独立进化:例如,传输层的TCP协议可以优化其算法以应对网络速度提升,而应用层的HTTP协议无需做任何修改。
  • 关注点分离:网络层(IP)只关心寻址和路由,不关心负载是TCP还是其他内容。

封装的数据包结构 📦

那么,封装在数据包中具体是如何表现的呢?每个协议层的数据单元通常由三部分组成:

  1. 头部(Header):包含本层协议的控制信息,如地址、序列号等。
  2. 负载(Payload):即来自上层协议封装好的完整数据单元。
  3. 尾部(Trailer):部分链路层协议有,用于差错校验等。

以下是一个从应用层到链路层的封装示例流程:

HTTP GET 请求
    ↓ (封装为 TCP 段的负载)
TCP 段 [TCP头 + HTTP GET]
    ↓ (封装为 IP 包的负载)
IP 包 [IP头 + TCP段]
    ↓ (封装为 WiFi 帧的负载)
WiFi 帧 [帧头 + IP包 + 帧尾]

最终在链路上传输的字节流,最外层是WiFi帧的格式。

数据包的两种绘制方式 🖍️

在技术文档中,你可能会看到两种不同的数据包绘制方式,这源于不同的技术背景:

  1. “右边开头”法:头部画在右侧,数据从左向右发送。第一个发送的位在最右边。这种视角常见于硬件和网络设备设计,侧重于数据流的时序。
    [ 负载 ... 头部 ]
    

  1. “左边开头”法:头部画在左侧,数据从内存地址0开始存放。第一个字节在左边。这种视角常见于软件和协议规范(如IETF文档),侧重于内存布局和解析。
    [ 头部 ... 负载 ]
    

两种方式没有对错之分,了解其背景有助于阅读不同资料。

实战观察:Wireshark 中的封装 🔍

理论需要实践验证。使用网络封包分析软件(如Wireshark)可以直观地看到封装。

在Wireshark捕获的一个数据包中,你可以清晰地看到层层嵌套的结构:

  • 最外层被识别为 以太网(Ethernet II)帧
  • 深入一层,看到内部的 IP 协议包
  • 再深入,看到 IP 包负载中的 TCP 段
  • 最内层,则是 HTTP 协议的明文请求(如GET)。

点击每一行协议,Wireshark会在下方的原始字节数据中高亮对应部分,生动展示了“套娃”式的封装结构。

封装的强大之处:递归封装 🚀

封装并非一成不变的四层结构,它可以递归进行,实现复杂的网络功能。一个常见的例子是虚拟专用网络。

假设你需要通过公共互联网安全地访问公司内部网络:

  1. 你的电脑照常生成 HTTP 请求,封装进 TCP 段,再封装进目标为内部服务器的 IP 包内部IP)。
  2. 由于不能直接发送,你的电脑将这个内部IP包整个作为负载,用 TLS 协议加密保护。
  3. 加密后的 TLS 记录 被封装进一个新的 TCP 段。
  4. 这个新的 TCP 段 再被封装进一个目标为VPN网关的 IP 包外部IP)。
  5. 最后,这个外部IP包被放入链路层帧发送出去。

这个过程形成了递归封装:
HTTP内部TCP内部IPTLS外部TCP外部IP链路帧

通过这种灵活的封装,我们仅需保护到VPN网关的通道,就能安全地接入整个内部网络。

总结 🎯

本节课中我们一起学习了计算机网络的核心原理之一——封装。

  • 封装 是将分层和分组交换统一起来的机制,它通过将高层数据作为低层数据的负载来实现。
  • 封装保持了各层的关注点分离,允许协议独立发展和优化。
  • 数据包结构包含头部、负载和尾部,从内到外层层嵌套。
  • 封装可以递归使用,以实现像VPN这样的复杂网络服务,展示了其设计的强大灵活性。

理解封装,是理解数据如何在网络分层模型中流动的关键。

课程 P80:DNS 查询与资源记录详解 📡

在本节课中,我们将深入学习 DNS 查询的实际过程、消息格式以及构成 DNS 响应的核心单元——资源记录。我们将通过具体工具和示例,解析 DNS 消息的各个组成部分。


概述:DNS 查询流程回顾

上一节我们介绍了 DNS 查询的基本流程。本节中,我们来看看查询的具体格式和内部结构。

DNS 查询始于客户端向解析器发起递归查询。解析器可能从其缓存中直接回答,或者代表客户端向外部 DNS 服务器发起一系列非递归查询,最终将结果缓存并返回给客户端。


DNS 消息的核心:资源记录

所有 DNS 消息中的信息都表示为资源记录。理解资源记录是理解 DNS 工作原理的关键。

资源记录的通用格式相当简单,包含以下几个字段:

  • 名称:与此记录关联的域名。
  • 类型:记录的类型(例如 A 记录或 NS 记录)。
  • :通常为 1,代表互联网地址。
  • 生存时间:记录在缓存中有效的时长。
  • 数据:记录的具体内容,其长度由 rdlength 字段指定。

用代码描述其结构如下:

[名称] [类型] [类] [TTL] [rdlength] [rdata]

两种关键的资源记录类型

以下是两种最核心的资源记录类型:

  1. A 记录:将域名映射到 IPv4 地址。其数据字段包含一个 32 位的 IP 地址。
  2. NS 记录:指定负责该域名的权威名称服务器。其数据字段包含一个域名。

使用 dig 工具探索 DNS

探索 DNS 记录外观和类型的一个好方法是使用 dig 工具。

例如,执行命令 dig www.stanford.edu 会返回一个详细的 DNS 响应。这个响应不仅包含了我们请求的 www.stanford.edu 的地址信息,还可能包含规范名称记录、权威名称服务器列表以及它们的地址等额外信息。DNS 服务器倾向于在单个响应中提供大量附加数据,以减少客户端后续的查询次数。


DNS 消息的详细结构

一个实际的 DNS 消息结构在 RFC 1035 中定义。其结构如下:

  1. 头部:长度为 12 字节,包含事务 ID、标志位(如查询/响应、递归可用性等)以及四个计数器,分别指明后续四个部分各有多少条资源记录。
  2. 问题部分:包含查询的问题,例如查询 www.stanford.edu 的 A 记录。
  3. 答案部分:包含直接回答问题的资源记录。
  4. 权威部分:列出负责该域的权威名称服务器。
  5. 附加部分:提供可能与查询相关的额外信息,例如权威名称服务器的 IP 地址。

名称压缩技术

DNS 报文通常被限制在 512 字节内。为了高效利用空间,DNS 采用了名称压缩技术。

DNS 将域名(如 www.stanford.edu)分解为标签序列(wwwstanfordedu)。每个标签前会有一个长度字节。当同一个域名在报文中多次出现时,后续出现的位置不会重复存储完整的域名字节,而是使用一个指针。这个指针占用 2 字节,其前两位设置为 11,剩余的 14 位指向报文中该域名第一次出现的位置偏移量。

公式表示指针:若长度字节值 > 192,则它与下一字节共同构成一个指针:指针偏移量 = (字节1值 & 0x3F) << 8 + 字节2值

这意味着,在查看原始报文数据时,你可能会看到类似 0xc00c 的字节,这表示“名称内容位于本报文偏移量 12 字节处”。


在 Wireshark 中查看 DNS 报文

让我们通过 Wireshark 捕获的报文,直观地看看查询和响应的样子。

当我们执行 dig market.cs.stanford.edu 时,Wireshark 会捕获到一个查询报文和一个响应报文。

  • 查询报文:相对简单,主要在问题部分包含了完整的域名 market.cs.stanford.edu 的标签序列。
  • 响应报文:则复杂得多。在答案、权威和附加部分的资源记录中,其名称字段经常不是完整的字符串,而是像 0xc00c 这样的压缩指针,指向报文中较早出现的完整域名,从而显著减少了报文大小。

通过这种机制,一个包含了多条 A 记录、NS 记录和 IPv6 地址记录的响应,可以轻松地容纳在几百字节之内。


总结

本节课中,我们一起学习了 DNS 查询与响应的内部机制。我们深入探讨了构成 DNS 消息的基本单元——资源记录的格式和关键类型(A 记录和 NS 记录)。我们使用 dig 工具查看了实际的 DNS 响应,并分析了 RFC 1035 定义的 DNS 消息标准结构,包括头部、问题、答案、权威和附加五个部分。最后,我们揭示了 DNS 为了在 512 字节限制内高效传输而采用的名称压缩技术,并通过 Wireshark 验证了其在真实网络报文中的应用。掌握这些细节,有助于你更深入地理解域名解析的全过程。

课程 P81:DNS 查询与响应详解 🔍

在本节课中,我们将深入探讨 DNS 查询与响应的实际过程。我们将了解查询序列如何工作、各种 DNS 记录类型的作用,以及如何通过“胶水记录”解决 DNS 解析中的循环依赖问题。课程内容将结合具体示例,帮助你理解 DNS 协议在实际网络中的运作细节。


DNS 查询序列概述

上一节我们介绍了 DNS 资源记录的基本概念。本节中,我们来看看客户端发出 DNS 查询后,查询在网络中传递的实际序列。

从高层次看,客户端发出递归查询,解析器则发出一系列非递归查询,最终获取目标域名(如 stanford.edu)的地址记录。但我们需要了解这些查询和响应的具体内容、每个服务器需要知道的信息。这在配置名称服务器和域名时至关重要。


名称服务器遍历与“鸡与蛋”问题

一个主要挑战来自遍历 DNS 区域的概念。名称服务器通常从一个根缓存文件开始,其中包含根服务器的 IP 地址。从那里,可以获取顶级域(如 .edu)的名称服务器地址,进而获取二级域(如 stanford.edu)的名称服务器地址。

然而,这里存在一个“鸡与蛋”问题。考虑 NS 记录:当你查询一个域的名称服务器时,DNS 记录返回的是主机名。例如,查询 stanford.edu 的名称服务器,会得到类似 argus.stanford.edu 的主机名。但问题在于,我们如何获取这些名称服务器本身的 IP 地址?我们需要 IP 地址才能向它们发起查询,但它们只给出了主机名。


解决方案:胶水记录

DNS 系统中的解决方案是使用“胶水记录”。当 .edu 服务器提供 stanford.edu 的 NS 记录时,它不仅提供服务器的主机名,还会附加这些名称服务器的地址记录(A 记录或 AAAA 记录)。这些附加的记录就是胶水记录,它们存储在父区域(此处为 .edu)的服务器中。

这意味着,.edu 服务器在提供 stanford.edu 的 NS 记录时,会一并提供这些 NS 记录对应服务器的 IP 地址,从而打破了循环依赖,让解析器能够继续向下查询。


查询序列逐步解析

让我们通过一个具体例子,逐步解析查询 www.cs.stanford.edu 的 A 记录过程。我们假设本地没有任何缓存,并使用“非递归”模式进行查询。

以下是查询步骤:

  1. 查询根服务器:客户端向根服务器发起非递归查询,询问 .edu 域的名称服务器。根服务器响应,提供一组可用的 .edu 名称服务器及其 IP 地址(胶水记录)。

  2. 查询 .edu 服务器:客户端使用上一步获得的 IP 地址,向一个 .edu 名称服务器查询 stanford.edu 的名称服务器。.edu 服务器响应,提供 stanford.edu 的名称服务器(如 argus.stanford.edu)及其 IP 地址(胶水记录)。

  3. 查询 stanford.edu 服务器:客户端向 argus.stanford.edu 查询 cs.stanford.edu 的名称服务器。argus.stanford.edu 响应,提供 cs.stanford.edu 的名称服务器(如 mission.cs.stanford.edu)及其 IP 地址。

  4. 查询 cs.stanford.edu 服务器:客户端向 mission.cs.stanford.edu 查询 www.cs.stanford.edu 的 A 记录。最终,mission.cs.stanford.edu 返回 www.cs.stanford.edu 对应的 IP 地址。

通过这个过程,解析器将获得的记录(包括胶水记录)缓存起来,以提高后续查询的效率。


其他重要的 DNS 记录类型

除了 A 记录和 NS 记录,DNS 还定义了其他几种关键记录类型。

以下是几种常见且重要的记录类型:

  • CNAME 记录:规范名称记录。它表明一个域名是另一个域名的别名。例如,www.stanford.edu 可能是一个 CNAME,指向 www-v6.stanford.edu关键规则:如果一个域名有 CNAME 记录,则它不能同时拥有任何其他类型的记录(如 A、MX 记录)。

    www.stanford.edu.    IN    CNAME    www-v6.stanford.edu.
    
  • MX 记录:邮件交换记录。它指定负责接收发送到该域名的电子邮件的服务器。例如,查询 cs.stanford.edu 的 MX 记录,会返回其邮件服务器的主机名。与 NS 记录类似,响应通常也会包含邮件服务器的 A 记录作为附加部分。MX 记录包含一个“优先级”值,用于在有多个邮件服务器时确定首选服务器。

    cs.stanford.edu.    IN    MX    10    mailgate.cs.stanford.edu.
    
  • SOA 记录:起始授权机构记录。它提供关于该 DNS 区域的管理信息,如主名称服务器、区域管理员的邮箱、序列号、刷新间隔等。

  • TXT 记录:文本记录。允许将任意文本与域名关联,常用于域名所有权验证、邮件安全策略(如 SPF、DKIM)等。

  • PTR 记录:指针记录。用于反向 DNS 查找,根据 IP 地址查询对应的域名。

  • AAAA 记录:IPv6 地址记录。用于将主机名映射到 IPv6 地址(128 位)。

    host.example.com.    IN    AAAA    2001:db8::1
    

记录类型间的交互与注意事项

不同记录类型间的交互可能产生微妙影响。一个重要的案例是 MX 记录不应指向 CNAME 别名

原因在于:MX 记录是供邮件传输代理等机器使用的。如果 MX 记录指向一个 CNAME,则解析器需要先解析 CNAME 找到规范名,再查询规范名的 A 记录,这引入了额外的查询层次,降低了效率且可能增加故障点。此外,由于 CNAME 记录不能与其他记录共存,这种设计实际上形成了一种“负激励”,鼓励管理员直接将 MX 记录指向具有 A 记录的主机名。

例如,如果 cs144.stanford.edu 是一个 CNAME,而你将 MX 记录指向它,那么在查询 MX 记录时,虽然会返回 cs144.stanford.edu,但无法同时附加其 A 记录(因为它没有 A 记录),迫使邮件服务器必须进行额外的 DNS 查询来解析这个 CNAME。


总结

本节课中,我们一起学习了 DNS 查询与响应的详细过程。我们探讨了 DNS 解析中遍历区域时遇到的“鸡与蛋”问题,并了解了通过 胶水记录 如何解决 NS 记录的循环依赖。我们还逐步解析了一个完整的 DNS 查询序列。

此外,我们介绍了多种重要的 DNS 记录类型,包括 CNAMEMXSOATXTPTRAAAA 记录,并特别讨论了 MX 记录不应指向 CNAME 别名的最佳实践及其背后的设计考量。理解这些细节对于配置和管理可靠的 DNS 服务至关重要。


计算机网络课程 P82:DHCP 动态主机配置协议 🖧

在本节课中,我们将学习动态主机配置协议(DHCP)。DHCP 是您每天访问互联网时都会用到的协议,它负责自动为网络中的设备分配必要的网络配置信息。

概述

主机要在 IP 网络上通信,需要获取几个关键信息。过去,这些信息需要手动配置,效率低下且不灵活。DHCP 协议的出现,解决了这些问题,实现了网络配置的自动化和动态管理。

主机通信的必要配置

一台主机要在 IP 网络上进行通信,需要获取以下三样核心信息:

  1. IP 地址:主机在网络中的唯一标识,用于发送和接收数据包。
  2. 子网掩码:用于区分哪些设备属于同一个本地子网。
  3. 网关路由器地址:当通信目标不在本地子网时,数据包需要发送到的“下一跳”地址。

此外,通常还需要第四样非常有用的信息:

  1. 域名系统服务器地址:用于将人类可读的域名(如 www.cnn.com)转换为机器可读的 IP 地址。

手动配置的局限性

在 DHCP 普及之前,网络配置需要手动完成。用户需要从系统管理员处获得一张写有上述四项信息的纸条,然后手动输入到计算机的网络设置中。

这种方法存在几个主要问题:

  • 缺乏灵活性:如果计算机被移动到另一个网络位置(例如从办公室搬到会议室),原有的配置将失效。
  • 管理效率低下:IP 地址等资源通常是按年分配的,即使一台机器只使用几天,也会长期占用一个地址,导致资源浪费。
  • 回收困难:难以有效追踪和回收不再使用的 IP 地址。

DHCP 的工作原理

DHCP 通过客户端/服务器模型,动态地为客户端分配网络配置。服务器为配置信息设置一个“租期”,客户端可以在租期结束前续租,这使得资源管理变得高效。

以下是 DHCP 交互的基本流程,通常被称为 DORA 过程:

  1. DHCP Discover:客户端首次加入网络时,会广播一条 DHCP 发现 消息,寻找网络中的 DHCP 服务器。
  2. DHCP Offer:收到发现消息的 DHCP 服务器会回应一条 DHCP 提供 消息,其中包含一个可用的 IP 地址和其他配置参数。
  3. DHCP Request:客户端从收到的多个“提供”中选择一个,并向该服务器广播一条 DHCP 请求 消息,正式申请该配置。
  4. DHCP Acknowledge:被选中的服务器最终发送一条 DHCP 确认 消息,正式将配置分配给客户端,租期开始。

此外,还有一个可选步骤:

  • DHCP Release:客户端可以主动发送 DHCP 释放 消息,提前归还 IP 地址。不过在实践中,客户端通常只是等待租期过期。

消息交换示例

让我们通过一个例子来具体看下这个过程。假设网络中有一个客户端和两台 DHCP 服务器(服务器A和服务器B)。

客户端 -> 广播: DHCP Discover
服务器A -> 客户端: DHCP Offer (IP: 10.33.1.94)
服务器B -> 客户端: DHCP Offer (IP: 10.33.3.188)
客户端 -> 广播: DHCP Request (请求服务器A的配置)
服务器A -> 客户端: DHCP Ack (确认分配 10.33.1.94)

客户端通过广播发送 DHCP Discover。服务器A和B都回复了 DHCP Offer,提供不同的IP地址。客户端选择了服务器A的提议,并广播 DHCP Request 指明选择。最后,服务器A发送 DHCP Ack 进行确认。

技术细节

在初始阶段,客户端还没有 IP 地址,因此它使用特殊的地址进行通信:

  • 源IP地址0.0.0.0
  • 目标IP地址255.255.255.255 (广播地址)
  • 传输协议:使用 UDP 协议。
  • 端口号:客户端从 UDP 68 端口发送消息,目的地是服务器的 UDP 67 端口。

DHCP Offer 消息中不仅包含 IP 地址,还以“选项”的形式包含了其他所有配置信息,例如:

  • option (1):子网掩码 (如 255.255.248.0)
  • option (3):路由器/网关地址 (如 10.33.0.1)
  • option (6):DNS 服务器地址列表

总结

本节课我们一起学习了 DHCP 协议。我们了解了主机网络通信所需的配置信息,回顾了手动配置方式的弊端,并深入探讨了 DHCP 如何通过 Discover、Offer、Request、Acknowledge 四个步骤动态分配这些信息。DHCP 通过引入“租期”概念,极大地提高了 IP 地址等网络资源的管理效率和灵活性,是现代网络能够即插即用的基石。

课程 P83:应用与NAT回顾 🌐

在本节课中,我们将学习当今互联网上的几种主要应用,以及网络地址转换器如何使这些应用的部署和运行变得复杂。我们将回顾NAT的工作原理、DNS系统、HTTP协议以及BitTorrent等应用的核心机制。


NAT:网络地址转换器 🔄

上一节我们介绍了互联网应用的基本背景,本节中我们来看看网络地址转换器。NAT是一种路由器,它允许多个设备共享一个公网IP地址。其工作原理是重写经过它的数据包。

该设备拥有一个用于与外部世界通信的外部地址,这是一个可公开路由的IP地址。同时,它管理着一个私有内部地址子网。

例如,私有地址范围可能包括所有以 10.*.*.*192.168.*.* 开头的IP地址。NAT设备会为自己分配一个私有地址(如 192.168.0.1),并将子网内的其余地址分配给内部网络中的设备。常见的家庭无线路由器通常就扮演着NAT设备的角色。

当内部网络中的设备通过NAT向外部互联网发送数据包时,NAT会修改数据包的头部信息,使其看起来像是从NAT的单一外部IP地址发出的。

这实际上是将来自不同内部地址的数据包,用同一个外部IP地址进行“伪装”。为了使这一过程正常工作,NAT需要一种方法来区分从外部返回的响应数据包,以便将其正确转发给内部对应的设备。

NAT设备通过修改传输层(如TCP或UDP)的端口号来实现这一点,用端口号来编码数据包来自哪个内部设备。这意味着NAT需要理解并修改传输层头部信息。

当来自外部互联网的数据包到达时,NAT会检查其目标端口号是否匹配到某个内部设备的映射。如果匹配,NAT会修改数据包并将其转发到内部网络。

由于NAT设备通常只在数据包流向外部世界时,才创建从内部IP地址和端口到外部端口号的映射,因此它不知道如何处理那些从外部世界主动发往内部设备的连接请求。

对于某些情况,这是一种安全优势:默认情况下,只能创建向外的连接,这保护了内部设备免受外部世界的直接攻击。但对于需要外部主动发起连接的应用(如某些P2P应用或服务器),这就成了一个麻烦,因为NAT会丢弃这些未经“预约”的TCP包。


以下是NAT的一些关键特点:

  • 设计多样性:存在多种NAT设计,以及将IP地址映射到外部端口号的方法,每种都有其复杂性。
  • 共识:普遍认为,简单、限制较少的NAT映射更好,因为它们能提供一种端到端连接性的外观。
  • 绕过技术:人们开发了一些技术来绕过NAT的限制,例如 NAT打洞同时打开


但本单元的核心要点是:NAT使得在互联网上部署某些应用程序变得困难。特别是那些需要外部世界主动与NAT后方设备建立TCP连接的应用。同时,部署新的传输协议也很困难,因为NAT设备可能不知道如何处理它们。

因此,当人们创建新的传输协议时,通常会选择伪装成TCP,或者运行在UDP之上。


DNS:域名系统 🗺️

上一节我们探讨了NAT带来的挑战,本节中我们来看看域名系统。DNS是一个运行在UDP之上的关键应用。一方面,它是关键的基础设施,没有它,互联网的实用性将大打折扣。另一方面,它本身也只是一个应用程序。

DNS的基本思想是使用层次化的名称来指向不同类型的信息记录。

例如:

  • 你可以查询 www.stanford.eduA记录(IPv4地址)是什么。
  • 你可以查询 stanford.eduNS记录(名称服务器)是什么。
  • 你可以查询 cs.stanford.eduMX记录(邮件服务器)是什么。

DNS通过一个服务器层次结构来工作。例如,要查找 www.stanford.edu 的地址:

  1. 首先询问根服务器,在哪里可以找到关于 .edu 域的信息。
  2. 然后询问 .edu 服务器,在哪里可以找到关于 stanford.edu 的信息。
  3. 最后向 stanford.edu 的权威服务器询问 www.stanford.edu 的地址。

为了减少查询负载,这些记录(地址记录和名称服务器记录)在每个步骤都可以被缓存很长时间。为了使缓存更有效,通常许多客户端会共享一个解析器(即为你执行DNS查询的计算机)。这样,解析器可以缓存所有查询结果并分享给客户端。

例如,只需要对 google.com 进行一次DNS查找,只要记录在缓存有效期内,所有使用同一解析器的客户端就都能获得结果,而不需要每个设备都去联系Google的DNS服务器。


HTTP:超文本传输协议 🌍

我们一直在使用的HTTP版本是 HTTP/1.1,它已经稳定运行了*二十年。HTTP运行在TCP之上,是一个请求-响应协议。请求和响应都是ASCII文本,这使得它易于阅读和调试。

HTTP/1.1 相对于 HTTP/1.0 的一个重大改进是引入了持久连接。在HTTP/1.0中,每个请求都需要一个独立的TCP连接。这意味着下载一个包含40个资源的页面,客户端需要打开40个TCP连接。

而HTTP/1.1允许客户端在同一连接上请求多个资源。这减少了用于TCP握手的时间开销,并且TCP连接有更多时间来增大其拥塞窗口,从而提升传输效率。

你可以利用这些知识大致计算下载一个完整页面及其所有资源所需的时间。你会发现,对于仅传输少量数据的连接,TCP连接建立时间可能是一个显著的开销。

最后,我们还简要了解了 SPDY 协议,它后来成为了 HTTP/2 的基础,旨在进一步解决HTTP/1.1的效率和延迟问题。


BitTorrent:对等文件共享 ⚡

你学到的第三个应用是像BitTorrent这样的对等文件共享协议。BitTorrent使用TCP,但与HTTP这种客户端-服务器模型不同,BitTorrent是由许多协作的客户端(称为)组成的大型集合。

为了共享大型文件(例如100MB),BitTorrent将文件分解为较小的片段,称为

每个BitTorrent客户端会与数十个(有时甚至上百个)其他客户端建立连接。客户端采用最稀缺优先的策略从其他客户端请求数据,即优先请求在群中最稀有的块,以避免该块从群中消失,同时也能消除传输瓶颈。

尽管BitTorrent乐于从许多对等节点请求数据,但在决定向谁发送数据时却非常谨慎。它试图建立一个激励系统:你想要获得数据,就需要贡献数据。

其工作方式是:一个节点会优先向那些给自己发送数据最多的对等节点发送数据。这样,从该节点获取数据的最佳方式就是先向它发送数据。偶尔,它也会开始向一个新的随机对等节点发送少量数据,以便在交换中发现新的潜在优质伙伴。这个算法被称为 “以牙还牙”算法


总结 📚

本节课中,我们一起回顾了当今互联网上的三种主要应用:DNS、HTTP和BitTorrent。我们看到了简单的UDP和TCP抽象如何以复杂而有趣的方式被应用。同时,我们也深入学习了网络地址转换器如何通过使对等节点发现和连接建立变得困难,从而复杂化了应用部署,并了解了一些绕过这些限制的技巧。现在,你应该对构建和理解网络应用所能使用的技术有了良好的基础认识。

课程 P84:路由基础 🧭

在本节课中,我们将学习计算机网络中一个核心概念:路由。我们将探讨数据包如何通过像互联网这样的大型网络,从源点传输到目的地,并了解构建路由表的关键算法。


概述

我们已经在前面的课程中多次假设,数据包能够从互联网的一端送达另一端。本节我们将深入探讨实现这一目标的具体机制和方法,即数据包如何被转发和路由通过互联网。


源路由的设想

一个最直接的思路是:让每个数据包自身携带它需要经过的所有路由器列表。这样,数据包就能根据内部包含的路径信息在网络中找到自己的路。

核心概念示例(伪代码)

数据包结构 {
    载荷数据;
    路径列表: [路由器A, 路由器B, ..., 路由器Z];
}

然而,这种方法被称为源路由。它被认为是低效的,并可能带来安全风险。因此,互联网并未采用这种方式。


互联网的实际方法:转发表

上一节我们介绍了源路由的设想,本节中我们来看看互联网实际采用的方法。互联网使用转发表。每个路由器都维护一个转发表,它告诉路由器:对于每一个目标网络地址(通常表示为前缀),应该将数据包发送到哪一个“下一跳”路由器。

因此,关键问题转变为:如何生成和填充这些转发表中的数据?


构建路由表:分布式算法

为了实现转发表的自动填充,我们使用算法。这些算法以分布式的方式运行,使得各个路由器能够自行计算出应放入转发表中的条目。

基本方法是:路由器共同协作,为网络构建一个生成树。生成树是一种没有环路的树形结构,它覆盖网络中的所有节点。树的根在目的地,叶子是所有可能的源点。这样,任何源点都可以沿着树的结构将消息发送到那个目的地。

以下是构建这种树状结构的两种广为人知的算法:

  1. 贝尔曼-福特算法(又称距离向量算法):在即将到来的视频中,你将看到它为何得名。
  2. 迪杰斯特拉算法(又称最短路径优先算法链路状态算法):这是目前更广泛使用的替代方法。

我们将在后续视频中详细描述这两种算法。


互联网的层次结构:自治系统

我们还将看到这些算法如何在今天的互联网上实际使用。首先,互联网是许多不同网络的集合,每个网络都有自己的管理域,称为自治系统

例如,斯坦福大学是一个自治系统(实际上它包含多个)。大型互联网服务提供商也可能拥有多个自治系统。自治系统有不同的类型,例如,像斯坦福这样的网络通常不负责在互联网核心中转发电信流量,它扮演着“边缘”或“存根”的角色。

在自治系统内部,主要使用两种路由协议:

  • RIP:一种距离向量协议。
  • OSPF:一种链路状态协议。目前,几乎所有人都使用OSPF来定义其自治系统内部的路由表。

然而,在自治系统之间,路由使用不同的协议:BGP(边界网关协议)。因为自治系统并不总是愿意完全暴露其内部网络结构,所以BGP增加了一些额外机制(例如记录数据包可能经过的路径),允许自治系统在隐藏内部细节的同时,提供足够信息让路由器选择路径。


总结

本节课中,我们一起学习了路由的基础概念。我们从简单的源路由设想开始,了解了互联网实际依赖的转发表机制。我们探讨了用于填充转发表的两种核心分布式算法(距离向量和链路状态),并认识了互联网的层次化结构——由自治系统构成,其内部和之间使用不同的路由协议(如OSPF和BGP)。至此,你应该对数据包穿越网络的不同策略有了初步的理解。

课程P85:路由基础 - 洪泛、源路由与生成树 🌳

在本节课中,我们将探讨数据包在网络中传输的几种基本方式。我们将从路由的核心概念和原理开始,了解数据包如何从源点A到达终点B,以及决定路径选择的各种考量因素。

概述 📋

无论我们使用第三层的IP地址进行路由,还是使用第二层的以太网地址和交换机,核心问题都是相同的:数据包应该如何选择路径?路径应该由源主机A选择,还是由网络中的其他实体决定?在选择路径时,最重要的指标是什么?是最短路径、最不拥堵的路径、随机路径,还是最安全可靠的路径?在接下来的内容中,我们将介绍几种解决这个基本问题的技术,并探讨不同的路径选择指标。

洪泛路由 🌊

洪泛可能是确保数据包至少能到达网络中所有目的地(包括目标B)的最简单方法。

以下是洪泛路由的工作原理:

  • 每个路由器在收到数据包后,会将其从所有接口转发出去(除了数据包到达的那个接口)。
  • 这个过程会逐跳重复,数据包会迅速扩散到整个网络。
  • 这种方法效率很低,所有链路都可能被重复使用多次,并且数据包可能形成环路,永远循环下去。

为了防止数据包无限循环,通常会使用跳数限制生存时间(TTL)字段,就像IP协议中所做的那样。

洪泛路由的优点是简单,不需要路由器维护网络拓扑状态。但由于其效率低下,通常只在特定情况下使用,例如当网络拓扑未知或不可信时,或者在某些过渡时期。

源路由 🧭

上一节我们介绍了由网络设备决定的洪泛路由,本节我们来看看由发送方主机决定的源路由。

源路由是指源节点在数据包头部填充它希望数据包经过的一系列路由器(即路径)。

例如,如果主机A要向主机B发送数据,它可能将路径指定为 R1 -> R3 -> R6。这样,沿途的路由器只需按照这个列表依次转发即可。

源路由是端到端原则的一个实际例子,所有路径决策都由终端主机做出。这意味着:

  • 网络本身不需要支持复杂功能。
  • 主机必须知晓网络拓扑并自行选择路径。
  • 数据包处理是变长的,可能携带很长的地址列表。

因此,源路由主要用于终端主机希望严格控制路径的场景。

转发表与逐跳路由 🗺️

现在让我们看看网络本身已经知晓路径的方法,即使用转发表进行逐跳路由

如果我们从A发送一个包到B,路径是 S1 -> S2 -> S4 -> B。那么每个路由器(S1, S2, S4)的转发表中都需要有相应的条目,指明去往目的地B的下一跳地址。

你可以将这种方式视为对源路由的一种优化。虽然源路由也能让包到达目的地,但让网络来承担这个常见的路由功能更为高效。当然,这需要一种方法来填充所有路由器的转发表,我们将在后续课程中学习。

生成树与路径选择指标 📏

在填充转发表时,一个常见的目标是创建生成树。生成树是一张覆盖网络中所有节点的图,并且它是一棵“树”,意味着其中没有环路。这确保了我们可以到达每个目的地,同时避免数据包陷入循环。

在计算生成树时,我们需要一个标准来决定选择哪一棵。这取决于我们的路径选择指标。以下是一些常见的指标:

  • 最短距离:最小化地理距离或链路物理长度。
  • 最少跳数:最小化经过的路由器数量。
  • 最低延迟:选择历史延迟最小的路径。
  • 最大吞吐量:选择负载最轻或最不拥堵的路径。
  • 最高可靠性:选择历史故障最少的路径。
  • 最低成本:选择使用成本(如资费)最低的路径。
  • 最安全:选择安全记录最好的路径。

实际上,我们可以使用以上任意一种或多种指标的组合。

最短路径生成树 🧮

通常,我们会根据选定的成本指标,为网络中的每条链路赋予一个成本(Cost),从而创建一个带权图。

一个自然的选择是为每个源到目的地的组合,寻找成本总和最小的路径,由此计算出的就是最短路径生成树

例如,如果我们为图中的链路赋予了成本,那么从各个主机到目的地X的最短路径可能如图所示。计算简单网络的最短路径生成树是直观的,但对于像互联网骨干网这样复杂的拓扑,我们需要自动化的路由算法来完成计算。

路由器之间会交换网络状态信息(这称为路由协议),并运行路由算法来计算最优路径,最终将正确的转发条目填入各自的转发表中。

其他路由类型 🔄

除了单播(一对一)和最短路径树,还有其他重要的路由类型。

多路径路由

到目前为止,我们假设去往特定目的地的所有数据包都走同一条路径(如最短路径生成树)。但这可能导致某些链路负载过重。

多路径路由允许将去往同一目的地的流量分散到多条路径上。这可以*衡网络负载,提高可靠性和资源利用率。需要注意的是,不同路径的延迟可能不同,可能导致数据包乱序到达,这通常由更高层的协议(如TCP)来处理。

广播与组播

之前我们讨论的都是单播,即一个包发送给一个目的地。但在某些应用中,一个主机可能需要将同一个包发送给多个目的地

  • 广播:发送给网络中的所有主机。
  • 组播:发送给一组特定的主机(例如,一个视频流发送给所有订阅者)。

一种低效的方法是源主机为每个目的地单独发送一个包。更高效的方法是让网络协助复制数据包。例如,源主机发送一个包,网络路由器在必要的分支点进行复制,并沿着一个覆盖所有目标主机的生成树进行转发。这大大节省了带宽和源主机的处理开销。

总结 🎯

本节课我们一起学习了网络中数据包路由的几种基础方法:

  1. 洪泛路由:简单可靠但效率低下,用于拓扑未知等特殊场景。
  2. 源路由:由发送方主机指定完整路径,体现了端到端原则。
  3. 转发表与逐跳路由:网络通过转发表优化路由过程,这是当前主流方式。
  4. 生成树与指标:构建无环路径需要依据延迟、成本、跳数等多种指标。
  5. 最短路径生成树:基于链路成本计算最优路径,需要路由协议和算法自动完成。
  6. 其他类型多路径路由用于负载均衡,广播/组播用于一对多通信。

在实践中,我们主要使用路由协议算法来计算最短路径并填充转发表。理解这些基础概念,是学习更复杂路由技术(如RIP、OSPF、BGP)的关键。

课程P86:距离向量路由与贝尔曼-福特算法 🧭

在本节课中,我们将学习一种名为“距离向量”的路由协议。我们将重点介绍其核心算法——贝尔曼-福特算法,了解路由器如何通过分布式协作,逐步找到通往网络中所有其他节点的最短路径。

概述

在上一节我们介绍了路由的基本概念,本节中我们来看看一种具体的分布式路由算法。距离向量协议的核心思想是:每个路由器维护一个“距离向量”,即它自己到达网络中所有其他路由器(或特定目标)的当前已知最短距离。路由器之间通过周期性地交换这些向量信息,并利用贝尔曼-福特算法进行迭代更新,最终所有路由器都能收敛,计算出到达每个目的地的最低成本路径(即最短路径树)。

问题定义:寻找最小成本生成树

我们要解决的核心问题是:一组路由器如何协同工作,找到连接所有节点的最小成本生成树?请注意,寻找路由器之间的最小生成树,与寻找包含所有终端主机的生成树是等价的,因为最终我们构建的是路由器之间的连通树。在后续例子中,我们将专注于路由器之间的路径计算。

分布式贝尔曼-福特算法详解

上一节我们定义了问题,本节中我们来看看贝尔曼-福特算法如何分布式地解决它。我们将通过一个具体案例来理解算法过程:计算从网络中所有其他路由器到达目标路由器R8的最小成本生成树。

算法基于以下设定和步骤:

  • 初始状态:每个路由器Ri维护一个值Ci,代表它当前所知到达目标路由器R8的最小成本。初始时,所有Ci都被设置为无穷大(∞)。
  • 核心公式/更新规则:每隔固定时间t秒,每个路由器Ri会执行以下操作:
    1. 向所有邻居路由器发送自己的当前Ci值。
    2. 同时,从每个邻居Rj那里接收对方告知的、邻居Rj到达目标R8的成本Cj
    3. 根据收到的信息更新自己的Ci。更新规则是:Ci = min( Ci, cost(Ri, Rj) + Cj ),其中cost(Ri, Rj)是路由器Ri到其邻居Rj的直接链路成本。
  • 收敛:只要学习到更低的路径成本,路由器就会更新自己的Ci。这个过程不断重复,直到所有路由器的Ci值不再变化,此时算法收敛,每个路由器都找到了到达R8的最短路径。

算法执行示例

以下是算法在示例网络中逐步运行的图示过程。我们将看到信息如何像波纹一样从目标R8向外扩散,并最终收敛。

(此处应插入图示,展示从初始∞状态,到第一跳、第二跳、第三跳信息传播后,各路由器Ci值的更新过程。图中会显示某些路径虽然跳数更多,但总成本可能更低,体现了算法寻找“最小成本”而非“最少跳数”的特性。)

通过示例可以看到,算法可能需要多轮迭代才能发现那些跳数更多但总成本更低的路径。当信息传播的跳数等于网络中最长无环路径的跳数时,算法必然能探索完所有可能路径,从而确保收敛到正确结果。

算法的特性与挑战

我们已经看到了贝尔曼-福特算法如何工作,现在我们来探讨它的一些重要特性及其面临的挑战。

收敛性与运行时间

  • 收敛性:算法总是收敛。因为初始值为无穷大,每次更新只会用更小的值替换当前值,成本值只会下降或保持不变。最终,所有路由器都会获知所有邻居通告的最低成本路径,从而稳定下来。
  • 最大运行时间:算法收敛所需的最大轮数(迭代次数)等于网络中最长无环路径的跳数。

“坏消息传播慢”问题

然而,贝尔曼-福特算法有一个著名的缺陷,即“坏消息传播慢”或“无穷计数”问题。当网络中出现链路失效时,算法可能需要很长时间才能收敛到新的正确状态,甚至会产生路由环路。

问题场景
假设有一条简单的线性拓扑路由器链:R1—R2—R3—R4,每条链路成本为1。初始时,R1知道通过R2到达R4的成本为3。
当R3与R4之间的链路断开后:

  1. R3发现直连链路失效,但它从R2处听说“我能以成本2到达R4”。于是R3错误地更新自己的成本为 cost(R3,R2) + 2 = 1+2 = 3,并通告出去。
  2. R2收到R3的新通告“我能以成本3到达R4”,于是R2更新自己的成本为 cost(R2,R3) + 3 = 1+3 = 4
  3. 此过程会持续下去,R3和R2相互“喂给”对方逐渐增大的错误成本值(4,5,6...),直到成本值增加到某个上限。

解决方案

为了解决“无穷计数”问题,实践中采用了以下几种技术:

以下是几种常见的修复方案:

  • 设置最大跳数:定义一个较小的最大值(如RIP协议中的16),当成本计数值达到该上限时,路由器即认为目标网络不可达。
  • 水*分割:路由器不会向某个邻居通告从该邻居学来的路由信息。这防止了环路中两个路由器相互依赖对方的信息。
  • 带毒性逆转的水*分割:路由器会主动向提供最佳路径的邻居通告该目的地的成本为无穷大,明确告知对方“不要通过我再去往那个目的地”。

实践应用与总结

贝尔曼-福特算法是距离向量路由算法的一个典型代表。这类算法的特点是每个路由器只维护一个到所有目的地的距离向量,并通过与邻居交换信息来分布式地、迭代地收敛到正确答案。

路由信息协议(RIP) 就是基于距离向量算法的经典协议,它曾在互联网上被广泛使用。其优点是实现简单,对路由器计算资源要求低。

然而,由于收敛速度慢和可能产生环路等问题,RIP等距离向量协议在大型网络中逐渐被链路状态路由协议(如OSPF)所取代。链路状态协议要求每个路由器收集整个网络的拓扑信息,然后独立地运行迪杰斯特拉最短路径优先算法来计算最短路径树,这通常能提供更快的收敛速度和更优的路径选择。

本节课中我们一起学习了

  1. 距离向量路由协议的基本思想。
  2. 贝尔曼-福特分布式算法的详细步骤与更新规则。
  3. 通过示例理解了算法的迭代收敛过程。
  4. 认识了算法“坏消息传播慢”的核心缺陷及其常见解决方案(如水*分割、毒性逆转)。
  5. 了解了该算法在历史上的实际应用(如RIP协议)及其在现代网络中被链路状态协议替代的原因。

课程 P87:链路状态路由与Dijkstra算法详解 🧭

在本课程中,我们将深入探讨路由协议中的链路状态算法,重点学习Dijkstra最短路径优先算法。我们将了解路由器如何通过交换网络拓扑信息,并独立计算出到达网络中所有其他节点的最短路径树。


链路状态算法概述

上一节我们介绍了距离向量路由的基本概念。本节中,我们来看看另一种重要的路由算法——链路状态算法。

在链路状态算法中,路由器首先会向网络中的所有其他路由器广播关于网络拓扑的全部信息。这些信息包括哪些链路是连通的、哪些是中断的,以及每条链路的成本。通过这种方式,每个路由器都能获得一张完整的网络拓扑图。

Dijkstra最短路径优先算法

Dijkstra最短路径优先算法是链路状态算法的一个典型代表。一旦路由器拥有了完整的网络拓扑图,它就会独立运行Dijkstra算法,计算出从自身出发,到达网络中所有其他路由器的最小成本生成树。

以下是Dijkstra算法的核心步骤:

  1. 初始化:将源节点(例如路由器R8)加入“最短路径树”集合。计算所有直接邻居节点到源节点的路径成本。
  2. 选择节点:从尚未加入树的节点中,选择一个到源节点路径成本最低的节点。
  3. 更新路径:将这个新节点加入最短路径树。然后,检查通过这个新节点,是否能以更低的成本到达其他尚未加入树的邻居节点。如果可以,则更新这些节点的路径成本。
  4. 重复:重复步骤2和步骤3,直到所有节点都加入了最短路径树。

我们可以用伪代码来描述这个过程:

# 伪代码示例
def dijkstra(graph, source):
    # 初始化距离字典,所有节点距离设为无穷大,源节点距离设为0
    distance = {node: float('infinity') for node in graph}
    distance[source] = 0
    # 初始化最短路径树集合和待处理节点集合
    shortest_path_tree = set()
    all_nodes = set(graph.nodes)

    while all_nodes:
        # 选择当前距离最小的节点
        current_node = min(all_nodes, key=lambda node: distance[node])
        all_nodes.remove(current_node)
        shortest_path_tree.add(current_node)

        # 更新邻居节点的距离
        for neighbor, weight in graph[current_node].items():
            new_distance = distance[current_node] + weight
            if new_distance < distance[neighbor]:
                distance[neighbor] = new_distance

    return distance, shortest_path_tree

算法实例演示

让我们通过一个具体的网络拓扑来演示Dijkstra算法的执行过程。假设我们有一个包含8个路由器(R1-R8)的网络,链路及其成本标注如下。

我们将以R8为源节点,计算其最短路径树。

以下是算法执行的迭代过程:

  • 步骤0:起始集合包含R8。候选节点为R3、R5、R6、R7。其中R7到R8的成本最低(成本1),因此首先将R7加入树中。
  • 步骤1:最短路径树包含{R8, R7}。候选节点更新为R3、R5、R6(原候选)以及R4(通过R7可达)。R4和R6到R8的成本均为2(例如,R8->R7->R4 成本为1+1=2)。我们选择R6加入。
  • 步骤2:最短路径树包含{R8, R7, R6}。继续从候选节点(R3, R5, R4)中选择成本最低的节点加入。以此类推,直到所有节点都被加入树中。

通过这样一步步地添加节点,最终我们就能得到从R8到所有其他路由器的最小成本生成树。

算法的特性与实际问题

关于Dijkstra算法,有几个重要的特性需要了解:

  • 时间复杂度:算法需要运行n次迭代(n为网络中的路由器数量),每次迭代选择一个节点。在最简单的实现中,其时间复杂度为 O(n²)
  • 应对网络变化:当链路状态发生变化(如链路故障或成本改变)时,发现变化的路由器会将此信息广播给网络中的所有其他路由器。所有路由器在收到更新后,会重新运行Dijkstra算法,基于新的拓扑图计算最短路径树。这种机制避免了“坏消息传播慢”的问题。
  • 实际应用:Dijkstra算法是OSPF(开放最短路径优先) 协议的基础,该协议在互联网中被广泛使用。

一个直观的理解方式

理解Dijkstra算法还有一种非常直观的方法。想象每个路由器是一个球,每条链路是一根绳子,绳子的长度等于链路的成本。将所有球放在*面上,并用对应长度的绳子连接它们。

当我们提起源节点(比如球A)时,整个结构会被拉起来。最终被拉紧的绳子,就构成了从A到所有其他节点的最短路径树。而那些松弛的、未被拉紧的绳子,则不在最短路径树上。这个物理模型生动地展示了算法“寻找最短路径”的本质。


本节课总结:我们一起学习了链路状态路由的核心——Dijkstra最短路径优先算法。我们了解了路由器如何通过交换链路状态信息来获取全网拓扑,并独立运行该算法,计算出以自身为根、到达所有目的地的最小成本路径树。我们还探讨了算法的步骤、特性及其在实际协议(如OSPF)中的应用。最后,通过一个形象的“球与绳子”模型,加深了对算法原理的理解。

课程P88:互联网路由与自治系统 🌐

在本节课中,我们将学习互联网如何通过分层路由来组织,特别是通过将网络划分为自治系统。我们将探讨自治系统内部使用的路由协议(如RIP和OSPF),以及它们之间如何通过外部协议(如BGP)进行互联。课程将帮助你理解互联网的基本结构和路由决策过程。


互联网的层次结构与自治系统 🏗️

上一节我们介绍了基本的路由算法。本节中我们来看看互联网的实际结构。由于互联网规模庞大,包含数百万台路由器,因此需要一种方法来管理路由信息的规模。

互联网被划分为多个自治系统。每个AS是一组由单一机构管理、使用共同路由策略的路由器网络。这种划分带来了管理上的自主性和可扩展性。

以下是关于自治系统的关键点:

  • 自主权:每个AS可以自由选择其内部使用的路由协议。
  • 类型:AS主要分为两类:
    • 单出口AS:只有一个连接点通往其他AS。
    • 多出口AS:有多个连接点通往其他AS。
  • 目的:这种结构支持互联网的有机增长,允许不同组织(如大学、ISP)独立管理自己的网络,并通过差异化服务促进竞争。

自治系统内部路由协议 🔄

了解了AS的基本概念后,我们来看看AS内部是如何进行路由的。AS内部使用的协议称为内部网关协议

以下是两种主要的内部路由协议:

  1. RIP
    • 全称:路由信息协议
    • 类型:基于距离向量算法,使用贝尔曼-福特算法
    • 特点:每30秒广播一次路由更新。如果180秒未收到邻居更新,则认为该路径失效。
    • 公式:距离向量更新规则:D_x(y) = min_v { c(x,v) + D_v(y) },其中c(x,v)是节点x到邻居v的成本,D_v(y)是邻居v到目标y的距离。

  1. OSPF
    • 全称:开放最短路径优先协议。
    • 类型:基于链路状态算法,使用迪杰斯特拉算法计算最短路径。
    • 特点:路由器通过洪泛方式广播链路状态信息,使所有路由器构建一致的网络拓扑图,然后各自计算最短路径树。
    • 代码逻辑(简化):
      # 迪杰斯特拉算法核心思想
      初始化所有节点距离为无穷大,起点距离为0
      while 存在未访问节点:
          u = 未访问节点中距离最小的节点
          标记u为已访问
          for u的每个邻居v:
              如果 通过u到达v的距离 < v的当前距离:
                  更新v的距离
                  记录u为v的前驱节点
      

数据包如何离开自治系统 🚪

现在我们知道如何在AS内部路由,那么数据包如何路由到其他AS呢?这取决于AS是单出口还是多出口。

  • 单出口AS(默认路由)
    • 对于目标地址不在本AS内的数据包,AS内的所有路由器将其转发给一个指定的默认路由器(即边界网关)。
    • 优点:路由表小,配置简单。

  • 多出口AS(出口选择)
    • 内部路由器需要为每个外部目标前缀选择使用哪个出口点。
    • 这导致路由表非常庞大(包含数万甚至数十万条目)。
    • 常见的出口选择策略有:
      • 热土豆路由:将数据包发送到离本路由器最*的出口点,以最快速度将包送出本AS。
      • 基于目的地的路由:选择离最终目的地最*成本最低的出口点,但这需要在AS内传播更多外部路由信息。

自治系统间的互联:BGP 🌉

AS内部的路由协议无法处理AS间的路由。因此,所有AS必须使用统一的外部网关协议进行互联,这就是边界网关协议

BGP(当前版本为BGP-4)的设计是为了解决互联网这个复杂、无严格层次结构的网状网络中的特殊问题:

  • 策略性:各AS有不同的商业目标和策略(如偏好某个供应商、成本考虑),BGP允许这些策略保持本地化和私有。
  • 可达性优于最优性:目标更多是找到一条可达的路径,而非计算理论上的“最短”路径,因为各AS对链路成本的衡量标准不同。
  • 信任与安全:AS之间可能存在竞争或不完全信任的关系,BGP需要在这种环境下工作。

BGP的详细机制将在后续课程中深入探讨。


互联网的整体结构图 🗺️

综合以上内容,我们可以描绘出互联网的大致分层结构:

  1. 第一层ISP:位于顶层,数量很少(全球约十几个)。它们之间完全互联,通常采用免费对等互联,互不结算费用。
  2. 区域ISP:位于中层,覆盖一个国家或地区。它们向上连接一个或多个第一层ISP,向下连接多个接入ISP。
  3. 接入ISP:位于底层,直接为最终用户(家庭、企业)提供互联网接入服务。

这种结构形成了“提供商-客户”关系链,数据流量通常自上而下流动,并伴随结算关系。为了节省成本,同层的ISP之间也可能直接建立连接。


总结 📚

本节课中我们一起学习了互联网路由的核心组织方式。我们了解到:

  • 互联网由众多自治系统组成,每个AS独立管理,运行自己的内部路由协议(如RIP或OSPF)。
  • 单出口AS使用简单的默认路由,而多出口AS需要复杂的机制来选择数据包的最佳出口点。
  • 所有AS通过BGP-4协议相互连接,以交换路由信息并实现全球互联。
  • 互联网整体呈现分层结构,包括第一层ISP、区域ISP和接入ISP,这种结构支撑着全球网络的运行与商业模型。

理解AS和分层路由是理解互联网如何作为一个整体工作的关键基础。

课程 P89:BGP边界网关协议详解 🚦

在本节课中,我们将要学习互联网中连接不同自治系统的关键协议——边界网关协议(BGP)。我们将了解BGP如何工作、它使用的路径向量算法,以及自治系统如何根据本地策略选择最佳路由路径。


BGP基础知识

上一节我们介绍了互联网的自治系统结构,本节中我们来看看连接这些自治系统的具体外部路由协议——BGP(边界网关协议)。

BGP不是链路状态或距离向量路由协议。它使用一种称为路径向量的机制。每个自治系统的边界BGP路由器会通告一条完整的路径,该路径是到达特定目的地前缀所需经过的自治系统列表,这被称为 AS路径

一个路径通告的示例如下:

网络前缀 171.6.1.0/24 可通过路径 [AS115, AS13] 到达。

这意味着,为了到达该网络前缀,数据包需要依次经过自治系统115和13。

使用路径向量的结果是,包含循环的路径在本地很容易被检测到。路由器只需检查AS列表中是否有重复的自治系统编号,然后可以简单地忽略或删除那些通告。这使得在网络中发现和消除路由循环变得非常容易。


BGP的关键特性与关系

BGP最重要的特性之一是,一个特定的自治系统可以根据本地策略,从邻居通告给它的多条路径中选择一条首选路径。这意味着,如果多个相邻的自治系统通告了到达同一前缀的不同路径,本地路由器可以选择它想要的任何一条,而不需要对其他方负责。

当链路或路由器发生故障时,路径会被撤回。撤回通告与路径通告类似,但会指明特定前缀通过该路径已无法到达。

BGP的运行基于两种核心关系:客户-供应商关系和对等关系。

客户-供应商关系

在这种层级关系中,供应商位于上层,客户位于下层。流量可以通过提供商流向客户或从客户处流出。这种关系的核心是经济流向:客户向提供商支付费用以传输其数据包。资金从客户流向提供商。

以下是一个客户-供应商层级的示意图:

         [提供商 AS]
             |
        [客户 AS1] -- [客户 AS2]

IP流量可以从客户流向其提供商,也可以从提供商通过其客户向下流动。这种层级关系是BGP策略制定的基础。

对等关系

对等关系通常发生在同一层级的提供商之间。关键原则是:对等体之间通常不提供中转服务。这意味着,如果两个自治系统是对等关系,其中一个不能使用另一个作为通道,将流量传输给第三个对等体。这种关系通常是免费结算的,因此没有经济激励来提供中转。

一个不允许的路径示例如下(黑色虚线):

[对等体AS1] ---X---> [对等体AS2] ---X---> [其他网络]

因为AS1和AS2是对等关系,AS2不会为AS1传输通往其他网络的流量。


BGP消息类型

BGP使用四种主要类型的消息来维持会话和交换路由信息:

以下是BGP的四种消息类型:

  1. OPEN:用于建立BGP对等会话。
  2. KEEPALIVE:定期发送,用于确认BGP会话仍然活跃。
  3. NOTIFICATION:用于在出现错误时关闭BGP会话。
  4. UPDATE:最重要的消息类型,用于通告新的路由撤回之前通告的路由

UPDATE消息包含前缀和路径属性。路径属性是关键信息,包括:

  • AS_PATH:数据包到达目的地需要经过的自治系统序列。
  • NEXT_HOP:指示应该将数据包发送给哪个下一跳路由器。
  • LOCAL_PREF:本地优先级,用于在多个路径中进行选择。
  • MED:多出口鉴别器,用于影响对等AS的入站流量选择。

这些属性帮助路由器在从不同邻居收到多个通往同一目的地的通告时,选择最佳的路径。


BGP路径选择过程

当路由器从不同邻居收到通往同一目的地的多个BGP路径通告时,它会按照一个确定的顺序来选择最佳路径。这个选择过程确保了决策的一致性和可预测性。

以下是BGP路径选择的标准顺序:

  1. 最高本地偏好:优先选择LOCAL_PREF值最高的路径。这是最重要的策略控制手段。
  2. 最短AS路径:如果本地偏好相同,则选择AS_PATH最短的路径(经过的自治系统数量最少)。
  3. 最低起源类型:优先选择通过BGP本身学习到的路径(IGP < EGP < INCOMPLETE)。
  4. 最低MED值:选择多出口鉴别器值最小的路径。
  5. 偏好eBGP over iBGP:优先选择通过外部BGP学到的路径,而非内部BGP。
  6. 到达NEXT_HOP的最低IGP成本:选择到达下一跳路由器内部开销最小的路径。
  7. 最低路由器ID:如果以上所有条件都无法区分,则选择通告者路由器ID最小的路径。

让我们通过一个例子来看AS_PATH如何影响选择。假设路由器收到两条通往同一前缀的通告:

  • 路径A: AS_PATH: [7018, 6341, 1129]
  • 路径B: AS_PATH: [7018, 3549]

如果两条路径的LOCAL_PREF相同,路由器将选择路径B,因为它具有更短的AS_PATH(只经过2个AS,而路径A经过3个AS)。


BGP策略实例:本地偏好

本地偏好是BGP策略中最强大的工具。它允许一个自治系统基于商业关系来优先选择某些路径。一个常见的策略是:

客户路由 > 对等路由 > 提供商路由

这种策略背后的逻辑是经济性的:

  • 来自客户的通告:意味着该目的地是付费客户,将流量发送给客户能带来收入。
  • 来自对等体的通告:通常是无结算关系,发送流量没有直接成本但也没有收入。
  • 来自提供商的通告:意味着需要向提供商支付流量传输费用,这是成本。

因此,自治系统会设置LOCAL_PREF值,例如:客户路由为100,对等路由为90,提供商路由为80。这样,路由器会优先选择来自客户的路径。

例如,在下图所示网络中,“Frank‘s Internet Barn”自治系统从客户、对等体和提供商都收到了通往同一前缀的路由。根据上述策略,它会优先选择来自客户的路径,并将流量发送到那个方向。

        [提供商] --- [Frank‘s AS] --- [对等体]
                        |
                    [客户 AS]

Frank‘s AS会设置本地偏好,使得来自客户的路径优先级最高。


总结

本节课中我们一起学习了边界网关协议的核心内容。

互联网上的所有自治系统都必须使用BGP-4进行互联,这是它们与邻居自治系统通信时必须使用的外部路由协议。BGP-4是一种路径向量算法,意味着每个路由通告都包含一个自治系统列表,这使得循环检测对路由器来说非常容易。

BGP为自治系统提供了一个丰富而复杂的策略接口,允许它们基于本地私有策略(如商业关系和流量工程目标)来选择路由。自治系统可以根据其需要,从不同邻居通告的路径中做出选择。这些策略的制定和后果是网络工程中一个深入且复杂的领域。

课程 P9:字节序详解 🧩

在本节课中,我们将要学习计算机通信中的一个基础但至关重要的概念——字节序。理解字节序对于编写网络协议软件至关重要,因为它决定了多字节数据在内存中的存储和传输方式。


通信协议的一致性 🤝

对于两个通信方来说,他们需要就交换的消息格式达成一致。如果一方假设消息是西班牙语的,而另一方假设它们是柬埔寨语的,计算机将无法通信。这意味着他们需要就消息的字段、排列方式、格式化方式以及表示方法达成共识,以生成要发送的消息。

软件通常需要在内存中创建消息的副本,然后传递给网卡。同样,当计算机接收消息时,网卡会将消息放入内存,软件随后可以访问它。理解这个过程的工作原理以及可能遇到的陷阱,对于理解网络协议并编写网络协议软件非常重要。


计算机内存模型 💾

上一节我们介绍了通信一致性的重要性,本节中我们来看看数据在计算机内存中是如何组织的。

让我们从计算机内存的一个简单模型开始。在大多数计算机中,内存以字节为单位组织,即八位内存块。一个程序拥有一个从地址零开始的地址空间。大多数现代计算机是六十四位的,这意味着内存地址是六十四位长。

因此,计算机最多可以处理到 2^64 字节,或约18.4万亿字节。在实际中,今天的计算机并不具有如此巨大的内存,它们通常拥有吉字节(GB)级别的内存,即 2^30 字节。

在这个例子中,我们的计算机有八个吉字节的内存。在左边显示了八个吉字节的内存,所以它的最大地址是显示的十六进制值 0x200000000

软件可以访问内存中的每一个字节,也可以访问字节组。例如,通过一条指令从内存中连续的八个字节单元加载一个六十四位整数。


字节序的概念 🔄

上一节我们了解了内存的组织方式,本节中我们来看看计算机如何表示多字节值,以及字节序的概念。

假设我们要表示数字一千二百二十四。这相当于十六进制 0x0400,或 4 * 256。这个数值需要十六位或两个字节来表示。

那么,哪个字节先来?是 0x00 还是 0x04?你如何在内存中布局多字节值被称为字节序,并且有两种主要选择。

以下是两种字节序的定义:

  1. 小端序:最不显著的字节位于最低地址。所以最不显著的字节首先出现在内存中。从计算架构的角度来看,这通常是最有意义的。

    • 公式内存地址增加方向从低位字节到高位字节
  2. 大端序:最显著的字节位于最低地址。大端模式对从左到右阅读的人类读者来说更有意义,因为它与数字的书写顺序一致。

    • 公式内存地址增加方向从高位字节到低位字节

总结 📝

本节课中我们一起学习了字节序。我们首先了解了通信双方对数据格式达成一致的必要性。然后,我们探讨了计算机内存的基本组织方式。最后,我们深入讲解了字节序的核心概念,即多字节数据(如整数)在内存中存储的两种顺序:小端序和大端序。理解字节序是处理网络数据、进行跨*台编程以及分析内存布局的基础。

课程P90:多播路由技术详解 🚀

在本节课中,我们将学习IP多播路由的核心技术与实现原理。多播允许数据包从一个源点高效地发送到一组特定的目的地,这在视频会议、广播电视等场景中至关重要。我们将从基本概念入手,逐步探讨其工作机制、协议实现以及在实际互联网中的应用与挑战。

概述与基本原理 📡

在之前关于路由基础的视频中,我们解释了IP多播路由的基本原理。本节将介绍与IP多播相关的一系列具体技术。

到目前为止,我们假设所有数据包都发送到单个目的地,即单播。但在某些应用中,我们希望数据包能被复制并发送到多个主机,即一组主机。例如,主机A可能希望发送数据包给B、C、X和E,而不发送给D。这可以是广播电视的场景,其中B、C、X和E都在观看同一电视或广播电台;也可以是视频会议,参与者的数量可能自动更新到大量主机。

虽然我们可以简单地将数据包在同一时间分别发送给每个目的地,但我们自然会问:网络能否或应该为我们复制数据包?例如,如果网络在路由器R1处复制数据包,那么它可以更高效地将数据包送达所有终端主机。这样,主机A只需发送一个数据包,但该数据包能正确送达所有目标目的地。因此,在本节中,我们将探讨实现这一目标的技术。

广播与泛洪技术 🌊

我们首先来看一种简单但基础的方法:泛洪。通过泛洪,数据包可以被送达大量主机。

在泛洪中,假设有一个源点A,它通过网络发送数据包到B。如果网络使用泛洪作为送达B的方法,那么来自A的数据包可以在路径上的每个路由器处被复制,并通过除数据包到达接口外的所有接口发送出去。

因此,来自A的数据包可以到达第一个路由器,然后从这里发送出去。当它到达下一个路由器时,它也可以从这里发送出去。最终,数据包将送达B。实际上,它将送达网络的每个叶节点。

泛洪的基本问题是:当网络拓扑中存在环路时,数据包可能会无限循环。因为当路由器从一个方向接收到数据包时,它会说:“这个数据包是从这个接口进来的,我将从所有其他接口发送出去。”这样,数据包就会永远循环下去。在生成树协议中,我们看到了这些循环是如何被打破的。接下来,我们将看一种不同的方法,从一开始就避免循环。

反向路径广播(RPB)技术 🔄

这种方法被称为反向路径广播,也称为反向路径转发。这是一种非常聪明的技术,被广泛使用,并且是早期互联网多播路由协议的基础。它基于一个非常简单的观察。

甚至在源点A开始发送多播之前,网络已经构建了一个从A可达所有主机的最小成本生成树。我们之前在单播路由协议中已经看到了如何做到这一点。例如,路由器R1已经知道如何计算所有向A发送数据包的最小成本生成树。因此,网络实际上已经有一个最小成本生成树。我们可以在发送多播数据包之前,利用该生成树来确定最佳路径。这就是为什么网络中会存在多播树,它是由所有路由器共同构建的,用于到达某个目的地。

因此,你可以使用这个生成树作为无环路的方法,将数据包发送给其他所有人。首先,让我描述广播的情况,这相当于泛洪,但没有数据包持续存在的环路。

现在想象一下,A正在向其他所有人发送数据包。这个数据包将包含一个地址(我们稍后会讨论地址),即与发送对象对应的组地址。但它也会包含源地址A,因为这个数据包来自A。沿途的每个路由器可以问一个问题:这个数据包到达的接口是否是从我到A的最短路径生成树的一部分?你可以在它的转发表中查找,看它是否正在向A发送单播数据包(而不是从A发送多播数据包)。如果它正在向一个单播地址发送数据包,这是否是它从这个路由器离开时将通过的路径?因此,它查找源地址A在其表中的记录。如果这是它发送单播数据包时将通过的接口,那么它将接受该数据包并从每个其他接口发送出去。

同样,当数据包到达R2时,R2会问同样的问题。如果它正在向A发送单播数据包,这是否是它将发送数据包的接口?答案是肯定的。因此,它将从每个其他接口发送出去。这有点像泛洪,但它问了一个更详细的问题:如果这是一个发送到A的单播数据包,我将通过哪个接口发送?

你可以看到,路由器R3也会问同样的问题,并回答“是”。因此,它将从所有其他端口发送数据包。然而,当这个数据包到达R2时,它将通过一个不在从A返回的绿色最短路径树上的接口到达。因此,R2将丢弃那个数据包,不会发送它。你可以看到,这实际上打破了循环。同样的情况也会发生在R8上,因为它不在绿色最短路径树上,所以那个数据包将被丢弃。你可以确信实际上不会有循环,因为数据包将跟随已经构建的生成树。这是一种聪明的想法,你可以看到为什么它被称为反向路径广播,因为它使用了与原始方向相反的生成树。

反向路径广播与修剪(RPB+Prune) ✂️

以上所有内容都很好,作为一种广播的手段。但我们在谈论多播。在这个特定情况下,数据包原本应该被送达所有终端主机,但实际上我们只想让它被送达每个终端主机,除了D。D是我们试图送达的主机集合之外的主机。

因此,一个简单的扩展是被称为“修剪”的技术。它通常被称为反向路径广播加修剪(RPB+Prune)。在这种方法中,那些没有连接到对接收该数据包感兴趣的主机的路由器会发送修剪消息。

在我们的例子中,D不是多播组的一部分。因此,路由器R6将发送被称为修剪消息的信息(我将其显示为点线)。它会说:“嘿,实际上,我没有任何对这个地址组感兴趣的终端主机。请不要再向我发送这个组地址的多播数据包了。”因此,它将修剪该组,并表示对此不感兴趣。

在这种情况下,这将从反向路径广播树中删除D。现在,那棵树只会到达对它感兴趣的终端主机。因此,它是一种减少广播开销的方法。然而,它显然在开始时仍然效率不足,因为在每个路由器开始修剪之前,它都会听到数据包。在一个非常大的网络中,这可能是不现实的。

总的来说,反向路径广播加修剪确保数据包以无环路的方式送达感兴趣的终端主机。没有附着在其上的感兴趣主机的路由器将发送修剪消息回向源。当然,它们可以使用源的单播地址来发送那个修剪消息,所以它会跟随树回向源。结果树是从源到感兴趣主机的最小成本生成树。因此,我们最终得到了一个高效的树,尽管到达那里的方法有些低效,因为我们必须首先与网络中的所有路由器进行通信。

源特定树与汇聚点 🌳

你可能在问:我们是构建一棵树,还是构建多棵树?在我的例子中,我展示了想要发送到目的地集合(B、C、X和E)的愿望。但如果是视频会议,当A说完话并向所有人发送数据包后,如果轮到B发送,那么B应该遵循的广播树是什么?

从B回到A,它们将以相同的方式跟随。但从B到C和B到X,以及从B到E,数据包更可能以不同的路径流动。换句话说,这棵树是源特定的最短路径树。从我之前的反向路径广播例子中应该很清楚,数据包将跟随源点对侧的最短路径生成树。因此,给定从每个源到每个目的地都有一个最短路径生成树,数据包走不同的路径并不奇怪。

因此,我们希望为每个发送者构建一棵单独的树,即源特定的树,以便所有数据包都跟随到终端主机的最短成本生成树。但在通信中,如果多播组的成员数量非常少,那么为每个源建立一棵树可能比建立一些汇聚点更容易。我们将在后面看到例子。

例如,我们可能会选举路由器R5作为汇聚点,所有多播数据包都将通过它。当每个人都在发送多播时,他们可以将数据包发送到R5。然后R5将构建到组中其他所有人的最短路径生成树。现在,R5有一个从其他源点到所有人的最短路径生成树(汇聚点到所有人),并且每个人都使用正常的单播路由方法来到达R5。因此,在实践中,存在一个设计选择:我们是保持一棵树,还是为每个源建立一棵树。

多播地址与组管理 📬

我已经告诉了你一些技术和原则,现在让我告诉你一些实践:今天互联网如何使用多播。我还没有提到关于地址的事情。在IPv4中,有一类地址不同于单播地址,它们是多播地址。多播地址有16位,因此有2^16种不同的多播地址。它们不对应于拓扑的特定位置,而是指一个组。所有在组中的接收者都将收到具有相同多播地址的数据包。这有点像一种间接寻址。路由器通常会维护对每个多播地址和源地址对的条目,以便它们可以将数据包发送到源特定的树。

我们还需要一种方式,让主机表示他们对加入一个组的兴趣。多播的一个有趣之处在于,一般来说,源不需要知道数据包被发送给谁。是网络、是树找出了这些信息。因此,树的每一片叶子,即每个主机,都需要表示对接收数据包的兴趣。它使用IGMP(互联网组管理协议,RFC 3376)来实现这一点。这是一种在终端主机与其直接连接的路由器之间运行的协议。主机会定期请求接收属于特定多播组的数据包。实际上,路由器会探测或向它们连接的所有主机发送请求,并问:“你对哪些多播组感兴趣?”然后主机会响应,说明他们想要接收哪些组。如果一段时间后没有收到任何回复,那么会员资格就会过期。换句话说,如果没有人对此感兴趣,路由器将不再发送属于这个多播组的数据包。这是一个被称为“软状态”的例子,状态仅被保持,如果没有重新表达兴趣,它就会过期。

互联网多播路由协议 🌐

让我来简要地谈谈互联网上的多播路由协议。

第一个多播路由协议被称为DVMRP(距离向量多播路由协议),在RFC 1075中描述。它在1980年代首次被引入,基本上使用了反向路径广播加修剪。因此,它基于单播路由协议已经构建好的树,我们只是打算反向使用它。另一种方法是称为PIM(协议无关的多播),它识别两种不同的多播模式。

一种被称为密集模式,预期将有很大一部分路由器参与多播。在这种情况下,RPB加修剪就足够了,因为大多数路由器都将参与,而且其中很少一部分需要修剪。因此,它使用了DVMRP或类似于DVMRP的方法,并在RFC 3973中进行了描述。

另一种方法被称为稀疏模式PIM,预计只有相对少数的路由器将参与多播。因此,做RPB加修剪将非常低效,因为在网络上将有太多的修剪消息。在这种情况下,它明确构建了汇聚点,发送的数据包将通过这些汇聚点加入一个小的生成树集合,从汇聚点到所有目的地。因此,投入了大量的工作来选择这些汇聚点,这是一个相当微妙的问题。

总的来说,DVMRP和PIM是广泛使用的方法。在提到的三个RFCs中描述的协议被实际使用。

多播的现状与挑战 🤔

实际上,多播的使用比最初预期的要少一些。最初预计它将用于大量的通信,因为在多播首次被构思时,世界上大多数的通信还是电视和广播,这是广播媒介。因此,人们预计这将成为一种非常常见的通信方式。实际上,在实践中,这并没有像最初所想的那样普遍。而且,过去二十年左右,通信已经变得更加个性化。我们倾向于要求我们特定想要观看的内容在特定时间观看,对广播的兴趣不如以前,除了像体育赛事、大规模的政治集会、火箭发射等事件。因此,这种个性化的时间调整大大降低了网络中对多播的需求。

此外,一些早期的实现(如DVMRP)效率很低,并且被发现存在扩展性问题,因此减少了一些人们对今天引入多播的热情。它被用于一些广播IPTV分发,并且一些应用也进行了一些应用层特定的多播,不使用网络基础设施,而是为它们自己构建了自己的覆盖树。

多播也引发了一些有趣的问题,特别是关于需要维护的状态,以便能够保持可靠的TCP通信。例如,想象一下,一个源正在向数百、数千或数百万的目的地发送数据包。如果你想要这种通信可靠,在其中保持跟踪哪些数据包已经在哪些目的地可靠地接收,这对单个源来说是一个恐怖的任务。实际上,任何需要状态的事情,比如流量控制或支持不同的用户在不同的终端支持不同的速度,如何做到这一点并不清楚,或如何使它安全,所有这些都是相当大的问题。从研究角度来看,人们对此产生了很大的兴趣,但一般来说,人们并不认为对这些问题有良好的解决方案。所以通常,多播主要用于传递主要单向数据的情况,例如电视,在这种数据从源未经修改地被移动到一组终端主机的情况中。

总结 📝

在本节课中,我们一起学习了IP多播路由的核心技术。我们从基本的泛洪方法开始,探讨了其环路问题,进而引入了反向路径广播(RPB)这一无环路解决方案。为了将广播优化为针对特定组的多播,我们学习了RPB加修剪技术。接着,我们讨论了源特定树与汇聚点的设计选择,以适应不同的应用场景。我们还了解了多播地址的格式、IGMP组管理协议的作用,以及互联网上实际使用的多播路由协议,如DVMRP和PIM。最后,我们审视了多播技术的现状、面临的挑战以及其主要的应用领域。多播是一项强大的技术,能够在特定场景下显著提升网络效率,但其实现和广泛应用仍面临诸多复杂问题。

课程P91:生成树协议(STP)详解 🌳

在本节课中,我们将继续学习路由的相关知识,并深入探讨一种用于以太网交换机的关键技术——生成树协议。我们将了解它如何防止网络环路,以及其工作原理和历史发展。

上一节我们讨论了路由的基本概念,本节中我们来看看在以太网环境中,交换机是如何通过生成树协议来实现无环路的网络通信的。

生成树协议概述

我们通常认为路由在网络层(如IP层)运行。然而,从更广义的角度看,任何将数据包从源点沿着选定路径发送到目的地的机制都可以视为路由。因此,以太网交换机也需要决定如何将数据包转发到正确的目的地。

以太网交换机根据以太网地址转发数据包。它通过“学习”地址来知道如何转发,但在学习过程中,广播消息可能导致网络环路。由于以太网帧没有TTL字段,这些广播包可能会在网络中无限循环。生成树协议就是为了解决这个问题而发明的。

生成树协议的核心思想

生成树协议的核心思想是为整个网络构建一个树形拓扑结构,并只使用属于这个单一生成树的端口来转发数据包,从而消除所有环路。

以下是生成树协议工作的基本步骤:

  1. 所有交换机通过交换特殊的控制消息(BPDU)来识别网络拓扑。
  2. 协议会选举出一个唯一的根交换机。
  3. 每个非根交换机确定其到达根交换机的最短路径端口(根端口)。
  4. 在每个网段上,选举出一个负责向根方向转发数据的端口(指定端口)。
  5. 所有既不是根端口也不是指定端口的端口将被阻塞,不转发用户数据,但依然可以收发BPDU以监控网络状态。

最终,整个网络形成一个无环的树状结构,所有数据都沿着这棵树进行转发。

生成树协议如何工作

让我们详细了解生成树协议的工作机制。

第一步:选举根交换机

协议开始时,每个交换机都认为自己是根交换机。它们会向外广播一种称为桥协议数据单元的控制消息。BPDU主要包含三个信息:

  • 发送者ID:发送该BPDU的交换机的标识。
  • 根ID:发送者当前认为的根交换机的标识。
  • 到根的距离:发送者认为自己到根交换机的跳数。

初始时,每个交换机发出的BPDU中,根ID就是自己的ID,到根的距离为0。当交换机收到其他交换机发来的BPDU时,它会进行比较:

  • 如果收到的BPDU中根ID更小,则采纳这个更优的根,并更新自己的信息。
  • 如果根ID相同,但到根的距离更短,也会采纳更优的路径。

采纳更优信息后,交换机会将到根的距离加1,并用自己的ID作为发送者,重新广播这个BPDU。这个过程会持续进行,直到网络中所有交换机都认同同一个ID最小的交换机为根交换机。

第二步:确定端口角色

确定了根交换机后,每个交换机需要确定自己各个端口在生成树中的角色。

  • 根端口:在每个非根交换机上,到达根交换机路径最短(成本最低)的那个端口被选为根端口。数据通过这个端口流向根交换机。
  • 指定端口:在每个物理网段(链路)上,需要选出一个负责向根方向转发数据的端口。通常,离根交换机更*的那个交换机上的端口会成为该网段的指定端口。
  • 阻塞端口:既不是根端口也不是指定端口的端口将被设置为阻塞状态。这些端口不转发用户数据帧,以防止环路,但它们仍然可以接收和发送BPDU,以便在网络拓扑变化时重新计算生成树。

最终,只有根端口和指定端口会转发数据流量,阻塞端口则处于闲置状态,从而打破了网络中所有可能的环路。

生成树协议的历史与发展

生成树协议最初由Radia Perlman于1985年发明。当时,以太网交换机被称为“网桥”,网络开始由大量网桥互联。为了避免广播风暴,需要一种快速可靠的方法构建无环路径,生成树协议应运而生。

1990年,IEEE将其标准化为802.1D协议。然而,传统的生成树协议收敛速度较慢,随着网络规模扩大,这个问题愈发突出。

因此,在2004年,IEEE引入了快速生成树协议(RSTP, 802.1w),显著提高了网络的收敛速度。

传统的STP和RSTP都为整个网络构建一棵树,数据包的路径可能并非源与目的地之间的最短路径,因为它们必须经过根交换机。

为了解决这个问题,IEEE在2012年引入了最短路径桥接协议(SPB, 802.1aq)。SPB使用了类似于OSPF等网络层路由协议中的链路状态算法(如Dijkstra算法),能够为每个源到每个目的地计算最短路径树,其理念更接*第三层的路由方式,并可能在将来得到更广泛的应用。

总结

本节课中,我们一起学习了生成树协议。我们了解到,STP通过在以太网二层构建一个无环的树状拓扑,有效防止了广播风暴和数据包无限循环的问题。其核心步骤包括选举根交换机、确定根端口和指定端口,并阻塞其他冗余端口。我们还回顾了STP从传统协议到快速生成树协议,再到最短路径桥接协议的发展历程,看到了网络技术如何不断演进以满足更高的效率和性能需求。理解生成树协议是掌握现代交换网络基础的重要一环。

课程 P92:IPv6 详解 🚀

在本节课中,我们将学习互联网协议版本六,即 IPv6。我们将了解它为何被提出、其地址格式、分配方式以及如何自动生成地址。通过对比 IPv4,我们将理解 IPv6 如何解决地址枯竭问题,并简化网络配置。


IPv6 的起源与必要性

上一节我们介绍了 IPv4 的基本概念。本节中我们来看看它的继任者——IPv6。

最初的 IPv4 地址设计是为了将多个不同的网络连接在一起,为私有网络提供全球唯一的标识符。然而,IPv4 的地址空间只有 32 位,大约能提供 2^32 个(约 43 亿)地址。在互联网早期只有几十个节点时,这看起来足够巨大,但现在已成为一个限制因素。

在任何编号方案中,实际使用率永远不会达到 100%。IPv4 地址的利用率大约只有 35%。挑战在于,如果没有 IP 地址,设备就无法在互联网上进行通信。发送 IP 数据包需要源地址和目的地址。

意识到 IPv4 地址可能耗尽,加上市场需求的推动,在 1994 年,一项针对新一代互联网协议的改进工作开始了,这就是 IPv6。IPv6 的基本协议在 1998 年以 RFC 2460 发布。此后经历了一段停滞期,但在 2003 年至 2006 年间,随着人们对 IPv4 网络挑战的理解加深,对 IPv6 的兴趣重新增加。

今天,IETF 内部以及多个政府(尤其是在连接性增长显著的国家和地区,如中国)都在大力推动 IPv6 的部署。IPv6 已在全球互联网上广泛使用。


IPv6 地址格式

了解了 IPv6 的必要性后,本节我们来看看它的地址具体是什么样子。

IPv6 地址不再局限于 32 位,而是拥有 128 位 的巨大地址空间。地址数量约为 2^128 个,这是一个天文数字(约 3.4 × 10^38)。理论上,这足以给地球表面每*方英寸分配超过 6.5 × 10^23 个地址。

一个 IPv6 地址被分为两部分:

  • 子网前缀:长度为 n 位,用于标识网络。
  • 接口 ID:长度为 128 - n 位,用于标识该子网中的特定设备。

这类似于 CIDR 表示法,其中子网掩码描述了网络标识符。

由于 128 位地址很长,且常包含大段的零,因此其书写方式与 IPv4 的“点分十进制”不同。IPv6 地址采用十六进制书写,形式为八个由冒号分隔的 16 位块(即四个十六进制数字)。

例如,一个完整的 IPv6 地址可能写作:2001:0db8:85a3:0000:0000:8a2e:0370:7334

为了简化,可以省略每个块中前导的零,并且一段连续的零块可以用双冒号 :: 表示一次。因此,上述地址可以简写为:2001:db8:85a3::8a2e:370:7334

地址后面通常会跟一个斜杠和数字,表示前缀长度,例如 /64,说明前 64 位是子网前缀。

如果你想在 Web 浏览器的 URL 中使用 IPv6 地址,需要将其放在方括号 [] 内,例如:http://[2001:db8::1]:80

此外,有一种特殊的 IPv6 地址格式用于兼容 IPv4,其前 96 位是固定的,后 32 位嵌入一个 IPv4 地址,例如:::ffff:192.0.2.1


IPv6 地址的分配

我们已经知道了 IPv6 地址的格式,那么这些地址是如何分配给组织或个人的呢?

回顾 IPv4,IANA 可以将包含 1600 万个地址的 /8 地址块分配给公司或组织。IPv6 的分配机制经历了多次迭代,基于经验得到了优化。

最初的建议(如 RFC 3177)指出,通常给终端站点分配 /48 的前缀,有时给 /64,极少情况下给单个设备分配 /128。经过多年实践,RFC 6177 更新了建议:分配的最小单位应该是 /64,而不是 /128。通常分配 /56/48 前缀,这为绝大多数组织提供了远超实际需要的地址空间。

当向区域互联网注册机构(RIR)申请地址块时,机构会根据申请者的实际需求决定分配的大小(例如 /56/48 等)。


自动配置 IPv6 地址

IPv6 庞大的地址空间不仅解决了数量问题,还极大地简化了网络配置。本节我们看看设备如何自动获取 IPv6 地址。

在 IPv4 中,我们通常依赖 DHCP 来请求一个地址。而在 IPv6 中,如果已知一个 64 位的子网前缀,设备可以自动生成一个全球唯一的 IPv6 地址,而无需中央服务器协调。

这主要利用了设备的以太网 MAC 地址。以太网 MAC 地址是 48 位的全球唯一硬件标识符,格式通常如:00:1A:2B:3C:4D:5E

IPv6 使用一种称为 EUI-64 的转换方法,将 48 位的 MAC 地址转换为 64 位的接口 ID。转换过程如下:

  1. 将 MAC 地址从中间分开,插入固定的 FF-FE
  2. 将首字节的第 7 位(全局/本地位)取反(即如果是 0 则置 1,如果是 1 则置 0)。

转换公式(伪代码)示例:

# 假设 MAC 地址为 00:1A:2B:3C:4D:5E
mac = “00:1A:2B:3C:4D:5E”
# 1. 插入 FF-FE
modified = mac[:6] + “FF-FE” + mac[6:]
# 结果:00:1A:2B:FF-FE:3C:4D:5E
# 2. 将第一个字节的二进制第二位取反 (00 -> 02)
# 最终接口ID:021A:2BFF:FE3C:4D5E

然后,将这个 64 位的接口 ID 与已知的 64 位子网前缀组合,就构成了一个完整的 128 位 IPv6 地址:[子网前缀]:[接口ID]

这种方法在 RFC 4291 中定义。它赋予了地址分配极大的灵活性,并简化了网络管理,因为设备可以“即插即用”,无需手动配置或运行 DHCP 即可获得一个可路由的地址。


总结

本节课中,我们一起学习了 IPv6 的核心知识。

我们首先了解了 IPv6 诞生的背景,即为了解决 IPv4 地址枯竭的问题。接着,我们深入探讨了 IPv6 的 128 位地址格式、其十六进制加冒号的书写规范以及简写规则。然后,我们学习了 IPv6 地址的分配策略,通常以 /48/56 为单位分配给组织。最后,我们掌握了 IPv6 的一大优势——无状态地址自动配置(SLAAC),它利用 EUI-64 算法将设备的 MAC 地址转换为接口 ID,从而自动生成全局唯一的 IPv6 地址,极大地简化了网络部署和管理。

总而言之,IPv6 凭借其*乎无限的地址空间和更简化的配置机制,正在成为支撑未来互联网发展的基石。


计算机网络课程 P93:路由基础 🧭

在本节课中,我们将学习数据包在网络中如何被路由到目的地。我们将探讨单播数据包路由的四种基本方法,并深入了解构建路由表的核心算法。


单播数据包路由的四种方法

上一节我们介绍了课程目标,本节中我们来看看路由器将数据包从源主机发送到目的主机的四种基本策略。

1. 广播

路由器可以将数据包广播到网络的所有链路。数据包到达路由器时,会被复制到除接收接口外的所有接口。这确保了广播数据包最终会遍历网络的所有链路,从而能够到达网络中的任何主机。

这种方法显然非常低效且成本高昂,并且需要结合防止数据包无限循环的机制。广播通常在不确定时使用,例如当网络拓扑发生变化,且没有其他方法确定能到达所有主机时。一个实例是OSPF路由器在交换链路状态信息时,会在OSPF域内广播链路状态数据包,从而使每个路由器都能知晓拓扑变化。

2. 源路由

我们可以在源路由中使用源路由。源主机将包含一系列跳点(即路径)的目的地列表放入每个数据包的头部,数据包将按照这个列表在网络中传输。

这要求源主机知道整个网络拓扑。源路由意味着我们不需要在网络中交换路由表信息,路由器也不需要维护转发表。可以说,源路由非常符合“端到端原则”,即不应让网络承担知晓所有路径的责任。

但在实践中,源路由很少使用,主要原因在于安全性。网络管理员不喜欢源路由,因为它要求他们暴露自己网络的完整拓扑,以便源主机能向任何地方发送数据包。互联网设计者认为,在路由器中维护转发表是一项值得的优化,可以避免需要将整个最新拓扑信息分发给所有终端主机。

3. 使用转发表

路由器可以包含转发表,这正是当今普遍的做法。路由器不依赖源提供路由信息,而是自行维护转发表。转发表包含目的地址,并指示数据包应从路由器的哪个接口转发出去,以便更接*目的地一步。

当今所有的以太网交换机和互联网路由器都使用转发表。路由算法的核心任务就是填充这些转发表。

4. 生成树路由

最后,你学习了无源路由算法通常如何构建一棵以目的地为根的生成树。它是一棵树(避免环路),并且是生成树(为所有源主机提供到达给定目的地的方法)。

互联网上使用的路由算法(如OSPF和RIP)通过填充转发表,在网络中创建生成树。我们通常构建的是最小成本生成树,试图最小化跳数、延迟或数据包传输距离。


构建转发表的核心算法

上一节我们了解了路由的基本方法,本节中我们来看看两种广泛用于在路由器中构建转发表的核心算法。

以下是两种核心的路由算法:

  1. 贝尔曼-福特算法(距离向量算法)

    • 每个路由器构建一个从自身到网络中所有其他路由器的距离向量
    • 在连续的步骤中,路由器交换它们的向量,以找到每个目的地的最*邻居。
    • 经过有限次迭代后,算法收敛,每个路由器都得到一组转发表,指明如何通过最短路径将数据包路由到每个目的地。
    • 该算法是RIP(路由信息协议) 的基础。RIP的好处是算法是分布式的,路由器共同构建完整的转发表,这在互联网早期路由器计算能力有限时很重要。但RIP存在“计数到无穷”等问题,导致坏消息传播缓慢,现已大部分被OSPF取代。
  2. 最短路径优先算法

    • 该算法假设每个路由器都有计算能力,在获得完整网络拓扑后,可以自行构建转发表。
    • 路由器通过交换链路状态信息(描述哪些链路存在)来学习拓扑。
    • 一旦获得拓扑,每个路由器便开始计算自己的转发表,以便能到达网络中的其他主机。
    • 该算法因其简单和快速而具有优势,是OSPF协议的基础。OSPF在今天的企业和校园网中广泛使用。

路由的其他重要方面

除了RIP和OSPF,我们还需要了解路由的其他四个关键方面。

分层路由

互联网使用分层路由将路由问题分解为更易管理的部分。在自治系统内部,使用域内路由算法(如OSPF)路由数据包。自治系统之间则使用BGP(边界网关协议) 交换路由信息。

例如,斯坦福大学在校园内使用OSPF,同时使用BGP与互联网上的其他自治系统交换信息。BGP是当今互联网上自治系统间交换路由信息的唯一标准方式。每个AS向其邻居通告其可达的前缀,数据包便能通过一系列AS路径到达互联网上的任何目的地。

多播路由

多播路由是网络中的一种优化,旨在避免源主机需要向一组目的地多次发送相同的数据包。在90年代,多播非常流行,被认为将用于互联网电视等应用。尽管存在许多多播路由协议,但它们今天并未被广泛使用。这是因为大多数应用(如视频流)更倾向于按需提供单播连接,而且观看同一内容的人数通常不足以证明在网络层进行优化的价值。

生成树协议

最后,你学习了生成树协议。它并非真正的互联网路由协议,而是以太网网络用于创建无环路拓扑的机制。生成树协议允许一组交换机构建一个单一的生成树,从而避免广播风暴。


总结

本节课中,我们一起学习了数据包路由的基础知识。我们探讨了单播路由的四种方法:广播、源路由、使用转发表和生成树路由。我们深入研究了两种构建转发表的核心算法:贝尔曼-福特算法和最短路径优先算法,并了解了它们如何应用于RIP和OSPF协议。此外,我们还简要介绍了分层路由(BGP)、多播路由以及生成树协议,从而对网络路由有了一个全面的初步认识。

计算机网络课程 P94:链路层基础与工作原理 🖧

在本节课中,我们将深入探讨网络协议栈的底层——链路层。我们将学习数据是如何在物理媒介上传输的,以及链路层如何解决传输过程中遇到的各种问题。课程将涵盖通信的基本原理、不同链路类型(有线与无线)的工作方式,以及由此引发的网络层问题,如分片和时钟同步。

通信基本原理 📡

上一节我们介绍了本单元的学习目标,本节中我们来看看通信的基本原理。这部分内容处于计算机科学与电气工程的交叉领域。

我们将讨论信号、噪声以及信噪比。信噪比实际上决定了一条链路的潜在比特率容量。今天我们没有每秒百吉比特的链路层,原因之一就在于这些通信的基本数学原理。

基于此,我们将查看像位错误这样的问题。链路层通过使用错误纠正码来从中恢复。例如,在链路层帧中添加一些冗余信息,这样即使物理层和链路层出现几个位错误,接收方也能恢复并接收到正确的帧。

链路的实际构建 🔗

我们在这个单元中要学习的第二个事情是,这些链接是如何实际构建的。你或许记得从第一单元学到的知识:TCP/IP的薄层设计允许许多不同的物理层或链路层在下方运行,并仍然能使用互联网协议将它们连接在一起。

物理链接有不同的类别,我们将讨论其中的两种。

有线链路:以太网

以下是关于有线链路,特别是以太网的介绍。

  • 共享介质与CSMA/CD:以太网的原始版本使用了共享电缆,因此需要一种方法来共享该电缆。我们将学习被称为CSMA/CD的协议或访问控制机制,它允许我们共享那条物理电缆。
  • 现代以太网与交换机:今天,我们也将学习现代以太网的工作原理,它使用交换机。你在前一个单元中已经学习了一些关于交换机如何学习地址以及那些转发表是如何被填充的知识。

无线链路

现在我们来学习无线链路。无线与有线有很大的不同,不仅仅在于它是通过空气广播这一事实。

以下是无线链路的一些根本性不同特性,我们在构建实用系统时必须注意:

  • 信号可变性:无线信道中的信号本身会随时间变化,不像有线链路那样在同一条链路上始终具有相同的容量。信道会衰减,可能存在不同类型的干扰。
  • 多径干扰:信号可以走不同长度的路径并相互干扰。
  • 广播特性与安全挑战:因为信号是广播的,每个人都能听到,这引入了安全挑战,因为每个人都能听到你的通信内容。
  • 隐藏终端问题:这是指当两个客户端都与一个接入点通信时,它们可以愉快地与接入点对话,但由于彼此之间没有直接的信号联系,它们无法感知对方的存在。因此,网络中需要额外的协调机制,以确保它们在接入点处不会相互干扰。

链路差异带来的网络层后果 🧩

除了学习这些不同类型的链接外,我们还将学习由于这些不同类型的链接而产生的一个后果:不同类型的链接可以携带的最大数据包大小不同,这个大小被称为最大传输单元

例如,以太网可以携带长达1500字节的包。但是,其他链路可能只能传输最大到某个特定长度的包。

你们可能记得我们在前面提到过IP协议中的分片功能。当数据包从一个MTU较大的链路向下传输到一个MTU较小的链路时,分片是必要的,因为小MTU链路无法承载整个原始数据包。网络层会将其分解为一系列自包含的片段。这些片段直到到达终点主机时才会被重新组装,然后数据被传递给上一层。

你将了解这是如何工作的,以及IP协议内部使此工作得以实现的具体机制。

通信中的时钟同步问题 ⏱️

我们最后要学习的是关于通信信道中一个微妙而有趣的细节:时钟同步。

当两个主机或链路的两端在进行通信时,它们不可能使用完全相同的时钟。你无法让两个不同地方的时钟保持完全相同的频率和相位。当发送者发送数据时,它使用自己的时钟,这可能与接收者使用的时钟不同。

因此,我们需要以某种方式告诉接收者我们使用了什么样的时钟速率、频率和相位,以便接收端能正确解码数据。所以我们会学习编码技术来解决这个问题。


本节课中,我们一起学习了计算机网络链路层的核心知识。我们从通信的基本原理(信号、噪声、错误纠正)出发,探讨了有线的以太网(包括其历史协议CSMA/CD和现代交换机结构)与无线链路的根本性差异(如信号可变性、隐藏终端问题)。接着,我们了解了不同链路的MTU差异如何导致IP层的分片与重组。最后,我们认识了通信中时钟同步的重要性及其解决方案。理解这些底层机制,是构建稳定、高效网络应用的基础。

计算机网络课程 P95:物理层与链路层原理 - 香农容量与调制 📡

在本节课中,我们将学习物理层的两个核心概念:信道容量调制技术。我们将了解如何计算一个物理介质能传输数据的理论极限,以及如何将数字比特转换为可以在介质上传输的模拟信号。


信道容量与香农极限 📈

上一节我们介绍了物理层的基本角色。本节中,我们来看看一个通信信道传输数据能力的理论极限。

一个给定的通信信道在信息传输上存在一个理论极限。这个“信道”可以指任何传输介质,例如电线、无线电磁波或声波。这个极限被称为香农极限,由克劳德·香农确立。

对于一个通信信道,在特定(通常成立的)假设下,其信道容量(即每秒可以发送的比特数)可以通过一个公式很好地*似计算:

C = B * log₂(1 + S/N)

其中:

  • C 代表信道容量,单位是比特每秒 (bps)。
  • B 代表通信的带宽,即可用频率范围的大小。
  • S/N 代表信噪比,即信号强度 (S) 与噪声强度 (N) 的比值。

这个公式表明,我们能发送的数据量与带宽成正比,并受信噪比影响。提高信噪比(增强信号或降低噪声)可以提升容量,但这在工程上可能代价高昂。同样,构建极高带宽的硬件也非常困难,这就是为什么我们无法轻易实现任意高速通信系统的原因。


模拟信号的基本属性 🌊

理解了信道容量的概念后,我们来看看信息在物理层是如何被表示的。这通常通过模拟信号(如正弦波)来完成。

当我们谈论正弦波时,有几个关键属性需要关心:

  • 振幅:表示信号的强度或“音量”。
  • 波长:一个完整波的周期长度。波长 (λ) 和频率 (f) 通过波速 (c,如光速) 关联:c = λ * f
  • 频率:每秒完成的波周期数,单位是赫兹 (Hz)。我们通常使用一个频率范围,这个范围的大小就是带宽
  • 相位:波形在特定时间点的位置。

在通信中,我们通过改变波的振幅、频率或相位来编码信息。


调制技术:将比特转换为信号 🔄

我们已经知道信号的基本属性,本节中我们来看看如何通过调制技术,利用这些属性来表示数据比特。

调制是将数据比特转换为适合在信道中传输的波形信号的过程。以下是几种基本的调制方式:

以下是几种基本的数字调制技术:

  1. 幅移键控 (ASK):通过改变信号的振幅来表示比特。

    • 例如:小振幅代表比特 0,大振幅代表比特 1
    • 代码示例(概念):if bit == 0: send(signal_low_amplitude); else: send(signal_high_amplitude)
  2. 频移键控 (FSK):通过改变信号的频率来表示比特。

    • 例如:一个频率代表比特 0,另一个频率代表比特 1
  3. 相移键控 (PSK):通过改变信号的相位来表示比特。

    • 例如:0度相位代表比特 0,180度相位代表比特 1(这称为二进制PSK,BPSK)。

ASK 因其简单性在有线网络(如以太网)中广泛使用。PSK 则在信号强度可能不稳定的环境中(如无线网络、DSL)更具优势,因为相位变化比幅度变化更易于检测。


正交调制与IQ表示法 📐

单一的调制方式有其局限。为了在单个符号中传输更多比特,现代通信系统常结合使用相位和幅度调制,这引出了正交调制的概念。

任何中间相位的信号,都可以由两个相位相差90度(即正交)的基准信号(称为I路和Q路)的线性组合来生成。

信号 = I * cos(ωt) + Q * sin(ωt)

其中,I 和 Q 是系数。通过调整 I 和 Q 的值,我们可以合成出具有任意幅度和相位的信号。这种IQ调制方法在硬件上非常容易实现。

这种表示法的巨大价值在于,它可以用一个二维图形——IQ星座图——来直观地表示信号。

  • 图中一个点的角度代表信号的相位。
  • 点到原点的距离代表信号的幅度。

例如,BPSK在图上就是水*轴上的两个点(+1,0)和(-1,0)。QPSK(四相PSK,每符号2比特)则是四个点,通常位于坐标轴上。


符号与比特:物理层的传输单位 ⚙️

了解了信号如何表示后,我们需要明确物理层实际传输的数据单元。

在链路层,我们处理由比特组成的帧。但在物理层,传输的基本单位是符号。一个符号可以对应一个或多个比特,这取决于调制方式的复杂程度。

  • BPSK:1 比特/符号
  • QPSK:2 比特/符号
  • 16-QAM(16点正交幅度调制):4 比特/符号
  • 256-QAM:8 比特/符号

因此,物理层的工作是将来自上层的比特流,转换(映射)为一系列的符号进行发送。使用更密集的星座图(如256-QAM对比QPSK),可以在同样的带宽和时间内传输更多数据,但对信噪比的要求也更高。


现代通信中的调制技术应用 📶

最后,我们来看看这些调制技术在现实系统中的应用。

当今主要的通信系统广泛使用基于PSK的调制,尤其是结合了幅度和相位调制的正交幅度调制 (QAM)

  • BPSK/QPSK:用于Wi-Fi(802.11 a/b/g/n)、蓝牙低功耗等。
  • 16-QAM / 64-QAM / 256-QAM:用于高速Wi-Fi(802.11n/ac/ax)、4G LTE、5G等移动通信标准,以实现更高的数据速率。

有线系统(如以太网)则倾向于使用多电*的幅度调制(如PAM-5,PAM-16)。


总结 🎯

本节课中我们一起学习了物理层的核心原理:

  1. 香农容量公式 C = B log₂(1+S/N) 定义了信道传输数据的理论极限。
  2. 信息通过改变模拟信号的振幅、频率或相位来进行编码,这个过程称为调制
  3. ASK、FSK、PSK 是基本的数字调制方式。
  4. 现代系统普遍采用正交调制 (QAM),它可以用 IQ星座图 直观表示,并能高效地在硬件中实现。
  5. 物理层以符号为单位传输数据,一个符号可承载多个比特,更高的调制阶数能提升速率,但也需要更优质的信道条件。

理解这些基础原理,是学习后续更具体网络技术(如以太网、Wi-Fi)的重要基石。

📡 课程 P96:物理层与链路层原理 - 位错误

在本节课中,我们将要学习物理层通信中的核心概念——位错误。我们将探讨噪声如何影响数据传输,以及如何通过编码技术引入冗余来对抗位错误,从而更有效地利用信道容量。

📊 香农极限与信道容量

通信信道的理论容量由香农公式决定:

C = B * log₂(1 + S/N)

其中:

  • C 代表信道容量(比特/秒)
  • B 代表信道带宽(赫兹)
  • S/N 代表信噪比

这个公式表明,在实际应用中,可用的数据率受限于信噪比。信号越强或电路噪声越低,就能实现更快的数据传输。这是一个理论极限,它告诉我们无法做得更好,但并未指明如何达到这个极限。如今,一些系统正在接*这个极限。

通常,系统带宽是固定的(例如,Wi-Fi使用的未授权频谱受法规限制)。因此,系统通常致力于提高信噪比。信噪比提高后,可以通过缩短符号传输时间,或在每个符号中承载更多比特(即使用更密集的调制星座图)来提升数据率。

🎯 噪声如何导致位错误

上一节我们介绍了信道容量的理论,本节中我们来看看噪声在实际中如何干扰信号。

在理想的无噪声系统中,接收到的信号会精确地落在调制星座图的某个点上。然而,现实中的硬件电路和环境总会引入噪声。

  • 低噪声环境(高信噪比)下,接收到的信号点会在理想点周围轻微波动,但仍能清晰识别。
  • 高噪声环境(低信噪比)下,噪声可能导致接收到的信号具有完全不同的相位和幅度,从而可能被误判为星座图中的另一个点。

例如,本应被解读为比特序列 0000 的符号,可能因为噪声被误判为 00111010。这就是位错误的引入过程:当信噪比低到一定程度,某些符号就会被错误地记录或解读。

可以想象,如果一个星座图中只有两个距离很远的点(如BPSK),那么较大的噪声也可能不会导致误判。但对于一个拥有16个密集点的星座图(如16-QAM),同样的噪声水*就足以引入位错误。

因此,根据给定的调制方案和信噪比,可以通过理论分析计算出预期的位错误率。位错误率可以变得非常低,但由于噪声的随机性,它永远不会为零。

🔄 编码:对抗位错误的策略

由于存在非零的位错误概率,直接将数据包中的比特映射到调制符号往往不是最高效的方式。为了应对罕见的噪声峰值,系统会过度保守地选择调制方案,导致实际运行速率远低于香农极限。

因此,在实际的物理层处理中,我们会在发送数据前引入冗余,这个过程称为信道编码

以下是其工作流程:

  1. 原始数据(例如“Hello”的ASCII码)组成数据包。
  2. 通过错误纠正码对数据包进行编码,生成一个更长的比特序列。例如,48位的原始数据可能被编码为60位,增加了12位冗余。
  3. 编码后的比特序列再被映射到物理层的调制符号进行发送。
  4. 在接收端,即使传输过程中发生了几个比特的错误,利用编码引入的冗余,接收器也能恢复出原始的48位数据。

编码不是物理层特有的想法,但它是在物理层提升链路可靠性和有效吞吐量的关键方法。尽管编码使发送的比特变长了,但由于它允许我们使用更高阶、更高效的调制方案来对抗错误,系统的整体吞吐量在理论和实践中都得到了提升。

衡量编码效率的一个常用术语是编码增益(或码率),它是链路层比特数物理层比特数的比率。

  • 一个“1/2码率”的编码意味着:链路层长度为 n 的数据包,在物理层被转换为长度为 2n 的序列。
  • 一个“3/4码率”的编码则意味着每3个链路层比特,对应4个物理层比特。

📶 实例分析:802.15.4与802.11n

让我们通过两个具体标准来看看编码和调制是如何应用的。

IEEE 802.15.4 (ZigBee) 示例
802.15.4使用一种非常简单的编码:它将每4个链路层比特,映射到32个物理层“码片”。这些码片再通过QPSK(每个符号2比特)调制发送出去。

  • 这相当于一个 1/8 的码率(4 / 32)。
  • 如果链路层数据率是250 kbps,那么物理层的符号率计算如下:由于每个QPSK符号承载2比特,物理层需要支持 250 kbps * 8 = 2 Mbps 的速率,即每秒传输100万个符号。

IEEE 802.11n (Wi-Fi) 示例
更现代的802.11n标准提供了丰富的调制与编码方案组合,以适应不同的信噪比环境。

以下是其部分方案:

  • 调制方式:从抗噪性强的BPSK(每符号1比特),到高效的64-QAM(每符号6比特)。
  • 编码码率:从冗余度高的1/2码率,到效率更高的5/6码率。
  • 数据率:不同的组合产生不同的实际数据率。例如,使用64-QAM调制和5/6码率,在40MHz信道下,速率可达150Mbps。使用更宽的信道(40MHz vs 20MHz)能大致实现吞吐量翻倍。

🎓 课程总结

本节课中我们一起学习了物理层通信中的位错误及其应对策略。

我们了解到:

  1. 信道容量受香农公式限制,信噪比是关键因素。
  2. 噪声会导致接收端误判调制符号,从而产生位错误。位错误率可计算,但永不为零。
  3. 直接进行比特到符号的一对一映射效率低下。通过信道编码引入冗余,虽然增加了发送的比特数,但能纠正错误,从而允许使用更高阶的调制,最终提升整体吞吐量编码增益
  4. 实际标准(如802.15.4和802.11n)会根据信道条件,动态选择调制方式(如QPSK, 16-QAM)和编码码率的最佳组合,以在可靠性和效率之间取得*衡。

核心在于,物理层通过将链路层的“比特”转换为物理“码片”或“符号”来对抗真实世界的噪声。更密集的调制能带来更高吞吐量,但也更易受噪声影响;而编码则提供了对抗噪声、逼*信道容量的有力工具。

课程 P97:物理层与链路层 - 时钟与时钟恢复原理 ⏰

在本节课中,我们将学习数据通信中一个核心概念:时钟。我们将探讨发送方如何利用时钟发送数据,接收方为何需要知道这个时钟才能正确解码,以及当没有独立的时钟线时,如何从数据信号中恢复时钟信息。


数据传输与时钟的基本问题

在数据通信中,例如在以太网链路上,我们以特定的速率发送数据,如10 Mbps或1 Gbps。这意味着每个比特的持续时间是固定的(例如,10 Mbps时,每个比特持续100纳秒)。因此,发送方必须使用一个本地时钟来精确控制每个比特的发送时刻。

接收方也需要知道这个时钟,才能准确判断一个比特的结束和另一个比特的开始,从而正确解码数据。

核心问题在于:发送方和接收方没有完全相同的通用时钟参考。发送方使用的时钟频率,接收方无法精确知晓,必须自行从接收到的信号中找出。

所以,本课程将描述这个一般性问题,并讲解:

  1. 如何通过数据编码来嵌入时钟信息,以简化接收方的工作。
  2. 接收方如何提取时钟,并将其转换到自己的时钟域中使用。

异步通信:适用于短消息

上一节我们介绍了时钟同步的基本问题,本节中我们来看看一种简单的解决方案:异步通信。

想象发送方使用自己的时钟(TX CLK)发送数据序列 0, 1, 0, 1, 0。接收方也有一个名义上频率相同的本地时钟(RX CLK),但由于是独立生成的,两者存在微小差异。如果接收方时钟稍慢,其采样点会逐渐滞后。

公式示例:假设时钟偏差为 ±100 ppm(百万分之一),即 频率偏差 = 标称频率 × 10^{-4}。对于10 MHz时钟,最大偏差为 10,000,000 Hz × 0.0001 = 1000 Hz

随着时间推移,滞后的采样点可能错过比特中间的稳定区域,从而在比特边界附*采样,导致解码错误(例如,漏掉一个0比特)。

异步通信通过控制数据包长度来规避这个问题。它用于短消息传输,如红外遥控或传统串行总线。

以下是异步数据包的典型结构:

  • 起始位:一个显著的电*变化,标志数据包开始。
  • 数据位:有效载荷数据。
  • 停止位:标志数据包结束。

接收方检测到起始位后,等待半个比特时间开始第一次采样,之后每个比特周期采样一次。只要数据包足够短,在时钟漂移累积到足以导致采样错误之前,传输就已结束。

总结:异步通信通过使用起始/停止位和限制包长,在时钟存在微小差异时,能够可靠传输短消息。


同步通信:实际系统中的标准方案

异步通信不适合长数据包。在实际网络(如以太网)中,我们使用同步通信。本节将深入探讨其工作原理。

同步通信系统的核心挑战是:只通过一根线发送数据,接收方必须从中恢复出发送方的时钟。系统框图包含以下关键部分:

  1. 时钟恢复单元:接收输入信号,通过检测信号中的跳变(边沿)来确定发送方使用的时钟频率和相位。常用电路包括锁相环(PLL)或延迟锁定环(DLL)。
  2. 弹性缓冲区:这是一个特殊的FIFO(先进先出)缓冲区。它使用恢复出的发送方时钟写入数据,使用接收方本地时钟读出数据。其作用是吸收两个时钟之间的频率差异,实现从“发送方时钟域”到“接收方本地时钟域”的安全过渡。

整个流程为:编码数据 → 传输 → 时钟恢复单元提取时钟 → 用该时钟采样数据并写入弹性缓冲区 → 用本地时钟从缓冲区读出数据。


数据编码:为时钟恢复提供“线索”

为了让时钟恢复单元能工作,传输的信号中必须包含足够的电*跳变。如果发送一长串连续的10,接收方将无法确定时钟。因此,我们需要在发送前对数据进行编码。

曼彻斯特编码

曼彻斯特编码是一种简单的方法,它保证在每个比特周期内都至少有一次电*跳变。

编码规则

  • 比特0:表示为从高电*到低电*的跳变(下降沿)。
  • 比特1:表示为从低电*到高电*的跳变(上升沿)。

代码示例:数据 0 1 0 1 的曼彻斯特编码波形会在每个比特中间发生跳变。

优点

  1. 每个比特都有跳变,使时钟恢复非常容易。
  2. 实现了“直流*衡”,即长期来看,高电*和低电*持续时间相等,便于设置接收判决门限。

缺点:最坏情况下(如连续1),信号跳变频率是数据速率的两倍,相当于浪费了一倍带宽

4B/5B 块编码

为了提高带宽效率,可以使用块编码,如4B/5B编码。

工作原理:将每4位原始数据映射为一个5位的码字。在所有的32个(2^5)可能的5位码字中,只选用那些包含足够多电*跳变的码字(例如,避免连续超过3个相同比特)。

优点

  • 比曼彻斯特编码更高效,过载仅为 5/4 = 25%,而非100%。
  • 总能保证数据流中有足够的跳变供时钟恢复。
  • 多余的未使用码字可用于传输控制信息。

总结:通过曼彻斯特或4B/5B等编码,我们在数据流中嵌入了时钟信息,使接收端的时钟恢复成为可能。


系统总览与下节预告

现在,我们可以勾勒出完整的同步通信系统流程:

  1. 发送方使用本地时钟。
  2. 数据经过编码(如4B/5B或曼彻斯特编码),确保跳变。
  3. 编码后的数据通过链路发送。
  4. 接收方的时钟恢复单元分析信号跳变,恢复出发送时钟。
  5. 使用恢复的时钟对数据进行采样。
  6. 采样后的数据写入弹性缓冲区
  7. 接收方使用自己的本地时钟,从弹性缓冲区中安全地读出数据。

本节课我们一起学习了时钟在通信中的核心作用、异步与同步通信的区别,以及如何通过数据编码来辅助时钟恢复。

在下一个视频中,我们将深入探讨弹性缓冲区如何工作,以及如何设计它以确保永远不会溢出或读空,从而稳定地桥接两个独立的时钟域。

📡 课程 P98:前向纠错与里德-所罗门码

在本节课中,我们将学习前向纠错的基本概念,并深入探讨一种广泛应用的纠错算法——里德-所罗门码。我们将了解为何需要纠错码,以及如何通过添加冗余数据来显著提高数据传输的可靠性和效率。


为何需要前向纠错

上一节我们介绍了物理层和链路层的基本概念。本节中,我们来看看前向纠错。

对于一个给定的信号,其信噪比和调制方案决定了预期的比特错误率。即使信号强度很高,比特错误率也永远不会为零,总存在一定的出错概率。

在实际应用中,这意味着比特错误虽然不常见,但总会发生。如果直接将链路层的比特转换为物理层的比特,会非常低效。因为为了达到极低的比特错误率,所需的调制密度或符号速率会非常高,这将导致效率远低于香农极限。

这不是构建高吞吐量系统的理想方法。


编码与冗余

因此,我们需要进行编码。编码是一种通过添加数据冗余来弥补预期中不常见比特错误的方法。

以下是编码的核心思想:

  • 添加冗余的成本远低于其带来的收益。
  • 通过添加冗余,可以大幅提高数据链路的吞吐量。因为几乎所有数据包都能成功传输,而不是几乎都无法通过。
  • 这在理论和实践中都得到了验证。

我们谈论编码时,也常提到编码增益。它通常指链路层比特数与物理层比特数的比率。例如:

  • 1/2 码率:将一个链路层比特转换为两个物理层比特,每个比特都有一个冗余比特。
  • 3/4 码率:将三个链路层比特转换为四个物理层比特。

这个过程就是前向纠错。其思想是主动添加额外的冗余数据,以便能够纠正潜在的错误。它被称为“前向”纠错,因为这是发送方主动进行的,接收方无需请求重传即可自行解码和纠错,从而节省了信令交互的开销。


里德-所罗门码简介

有多种前向纠错算法可供选择。在本视频中,我们将重点介绍里德-所罗门码

选择它有两个主要原因:

  1. 应用极其广泛:CD、DVD、DSL线路、RAID-6存储阵列等众多通信和存储系统都使用它。
  2. 基本概念相对简单(尽管深入实现涉及更多数学知识)。

里德-所罗门码的核心数学思想基于多项式。

一个 k-1 次多项式(例如二次多项式 ax² + bx + c,其中 k=3)可以由 k 个点唯一确定。这意味着,给定三个 (x, y) 点,就可以唯一确定系数 a, b 和 c。


里德-所罗门码的工作原理

那么,这有什么用呢?以下是编码过程:

  1. 数据到系数:取 k 个数据块,将它们视为一个 k-1 次多项式的系数。例如,三个数据块成为系数 a, b, c。
  2. 计算点:在这个多项式上计算 n 个点(其中 n > k)。
  3. 发送点:发送这 n 个点,而不是原始系数。

解码时,由于原始多项式是 k-1 次,所以只需要接收到其中任意 k 个正确的点,就可以唯一地重构出多项式,从而得到原始的 k 个数据块(系数)。

这里有一个复杂性:我们不能直接使用任意大的整数作为点的值,否则表示它们会占用过多空间。实际中,这些运算是在一个有限域中进行的,这确保了所有值都能用有限的比特位表示。这是实现细节,我们暂不深入。

基本概念总结:将数据表示为多项式系数,计算并发送多项式上的多个点,接收方通过足够多的点重构多项式以恢复原始数据。


纠错能力

在通信系统中,我们关心两种错误:

  1. 擦除:知道错误发生的位置(例如,数据包丢失、磁盘扇区损坏)。
  2. 错误:不知道错误发生的位置(即通常意义上的比特错误)。

里德-所罗门码将 k 个数据块编码为 n 个码块(n > k)。其纠错能力如下:

  • 可以纠正最多 n - k 个擦除错误。
  • 可以纠正最多 (n - k) / 2 个错误。

一个常见的例子是 RS(255, 223) 码:

  • 这意味着取 223 字节的数据,编码为 255 字节。
  • n - k = 255 - 223 = 32
  • 因此,它可以纠正最多 32 个字节的擦除,或最多 16 个字节的错误

概念性流程:将数据分成 223 字节的块,视为一个 222 次多项式的系数。计算该多项式在 255 个点上的值(在有限域中计算,表示为字节),并发送这 255 个值。只要接收到至少 223 个正确的值,或错误值不超过 16 个,就能恢复原始数据。


实例分析

让我们通过一个具体例子来理解。假设我们使用 RS(7, 5) 码:

  • 每个数据字长 3 比特。
  • 取 5 个这样的数据字(共 15 比特),编码为 7 个码字(共 21 比特)。

假设原始数据有 48 比特。编码过程如下:

  1. 48 比特数据 + 填充位 = 60 比特(即 20 个 3 比特数据字,可分 4 组,每组 5 字)。
  2. 对每组 15 比特(5字)进行 RS(7,5) 编码,得到 21 比特(7字)。
  3. 总共发送 4组 * 21比特/组 = 84 比特。

由于是 RS(7,5) 码,它可以从每组(7个码字)中纠正最多 1 个错误或 2 个擦除

考虑传输中的比特错误:

  • 如果错误分散在不同组的码字中,每组最多只含一个错误,则可以全部纠正。
  • 如果两个错误落在同一组的两个不同码字中,则该组无法纠正。

尽管存在无法纠正的极端情况,但与完全不使用编码相比,系统的抗错能力已大大增强。


交织技术

物理层错误有时会集中爆发,形成连续的错误串,这比分散的随机错误更难处理。

为了提高对突发错误的抵抗能力,可以采用交织技术。

不使用交织时:数据按编码块顺序发送(A0-A20, B0-B20...)。一个长的突发错误可能损坏同一个编码块中的多个码字,导致超出其纠错能力。

使用交织时:发送顺序变为 A0, B0, C0,... A1, B1, C1,... 以此类推。这样,一个物理层的突发错误会被分散到多个不同的编码块中,每个块可能只受到一个错误的影响,从而更容易被纠正。

例如,一个 12 比特的突发错误,在使用交织后,可能会使 12 个不同的编码块各出现 1 比特错误。而 RS(7,5) 码每个块正好能纠正 1 个错误,因此整个突发错误得以纠正。不使用交织,则可能完全无法纠正。

因此,交织是一种非常常见且有效的、与纠错码结合使用的技术。


总结

本节课中,我们一起学习了:

  1. 前向纠错的目的:通过添加可控的冗余,高效应对信道中不可避免的错误,提升吞吐量。
  2. 里德-所罗门码的原理:基于多项式插值,将数据编码为多项式上的点,利用点的冗余来纠错。
  3. RS码的纠错能力:可纠正 n-k 个擦除或 (n-k)/2 个错误。
  4. 交织技术:通过打乱发送顺序,将突发错误分散化,极大提升纠错码对突发错误的抵抗能力。

里德-所罗门码因其强大的纠错能力和相对简洁的数学基础,成为从光盘存储到现代通信系统中不可或缺的一环。理解其基本原理,是深入理解现代数字通信和存储系统可靠性的关键。

计算机网络课程 P99:物理层与链路层 - MAC 与 CSMA/CD 原理 🖧

在本节课中,我们将学习链路层和物理层的基本概念,特别是介质访问控制(MAC)协议。我们将从最简单的随机访问协议 ALOHA 开始,逐步深入到以太网广泛使用的核心机制——载波侦听多路访问/碰撞检测(CSMA/CD)。通过本课,你将理解共享介质上如何协调多个主机发送数据,以及 CSMA/CD 如何工作。


概述:以太网与链路层

当我们今天将电脑连接到网络时,通常使用 Wi-Fi 进行无线连接,或者以太网进行有线连接。以太网是当今互联网上最广泛使用的链路层机制。

链路层覆盖了终端主机如何连接到路由器,以及路由器如何连接到下一个路由器。一般来说,IP 层的包被封装在一个链路层帧(大多数情况下是以太网帧)中,以便被发送到第一个路由器。

在本视频和下一个视频中,我将描述一种叫做 CSMA/CD 的东西,这是以太网工作的核心,并且深深地融入了原始的以太网设计。接下来,我将描述以太网如何多年来经历了其进化,以及以太网交换如何成为一种非常普遍的方式来扩展链路的范围,以覆盖连接到单个路由器的许多终端主机。


以太网与 OSI 模型

你经常会听到以太网被称为“第二层”。这可以追溯到我们在早期视频中看到的七层 OSI 模型。在四层互联网模型中,以太网是最低层。在七层 OSI 模型中,以太网涵盖了链路层和物理层这两个底层。因此,以太网经常被称为第二层。

  • 链路层:实际上只覆盖了帧格式,以及决定包何时可以在电线上发送的算法(即 CSMA/CD 机制)。
  • 物理层:覆盖了像连接器和电线上使用的电气信号这样的东西。

共享介质与 MAC 协议

以太网最初作为一种将多个计算机连接到同一根电缆上的手段开始。那根电缆被安排成一条长串或总线。实际上,一条粗大的黄色电缆蜿蜒地缠绕在墙壁上、天花板或地板下面,计算机将被连接到它。所有计算机都可以共享这根相同的公共线缆。

想法是,它们应该共享它,以便能够相互发送数据包。但是,每次只允许一个包通过电缆,否则,它将碰撞或干扰其他数据包。这就是我们所说的共享介质。以太网是多个主机共享同一根电缆的示例。

要共享介质,我们需要决定谁有权发送,以及何时发送。因为如果只有一个数据包可以在同一时间通过介质发送,我们需要决定介质何时变空闲,以及谁在下一次有机会使用它。这个机制通常被称为介质访问控制(MAC)协议。这些是决定谁有权发送下一个的协议或算法。

这里有一件事需要注意的是,你可能以前听说过以太网地址被称为 MAC 地址。它代表介质访问控制。尽管我们稍后会看到,以太网不再广泛使用早期的 MAC 机制(如 CSMA/CD),但那只是早期十兆比特每秒以太网的情况。


MAC 协议的类型

让我们来看看一些介质访问控制协议的例子。实际上,多年来已经描述、出版和发明了数十或数百种,并且许多都被标准化。但因为许多已经过时,我将专注于以太网使用的载波侦听多路访问/碰撞检测(CSMA/CD)。但我想把它放在一个更大的背景下。

总的来说,有两大类 MAC 协议:

  1. 随机访问协议:任何主机都可以在任何时间尝试发送。它不需要等待中央权威批准或轮到它。它只是试图发送。它可能会倾听并看看是否有其他人在说话,或者它可能直接继续。从随机性的角度来看,它可能随时开始说话。
  2. 确定性协议:如令牌传递,有一些方法可以明确控制谁下一个发送。最常见的方法是叫做令牌传递。一个特殊的包或令牌从一个主机发送到下一个主机。当您持有令牌时,您被允许发送数据包。当它完成发送后,将令牌传递给邻居,然后邻居有机会发送。

随机访问协议易于实现。当发送者的数量较小且随机发送数据时,它们可以提供很好的性能。但在负载非常重时,它们工作得不太好,因为它们可能会花费大量时间与其他数据包碰撞。确定性协议(如令牌传递)需要生成和维护令牌,并且令牌可能会丢失或被复制,因此这些通常已经过时并被更简单的以太网机制所取代。

当我们设计或选择 MAC 协议时,通常有一些目标:

  • 共享通道的高利用率。
  • 公*性,确保每个人都有发送机会。
  • 简单且低成本实现,以便广泛部署。
  • 对错误鲁棒,单个主机失败不会导致整个网络瘫痪。

ALOHA 协议:一个简单的例子

让我从一个例子开始,我将使用的例子是其中一个最早的媒体访问控制协议,叫做 ALOHA 协议。它是在夏威夷的 ALOHA 网络中使用的。

ALOHA 网络是基于无线电的。所有终端设备都会在一个频率上进行传输。如果一个终端设备有东西要发送,它会在频率零上发送到中央中继站。然后数据包将被重新传输到频率一上(一个单独的正交频道),广播给所有终端主机。

我们需要一种方法来决定谁可以何时发送。ALOHA MAC 协议非常简单:

  1. 如果你有数据要发送,发送它。
  2. 如果你的传输与其他传输碰撞,稍后重试。

你怎么知道它碰撞了?你会在频率零上发送,并在频率一上监听。如果回来的不是你发送内容的正确副本,你知道它一定碰撞了,因此你需要再次发送。

ALOHA 协议的好处是非常简单,它对终端主机的失败具有很强的抵抗力(如果主机停止发送,机制不依赖于它)。协议是分布式的,在所有终端主机上都独立运行。

  • 在负载低时:延迟很小,几乎任何有数据要发的主机都会找到通道空闲,第一次就顺利通过。
  • 在负载高时:发送碰撞的包可能会浪费很多时间,成功的机会降低。研究表明,在负载高时,只能实现大约 18% 的吞吐量,超过 80% 的时间都被用于碰撞的传输。

显然我们需要提高性能。在 1970 和 80 年代,有很多关于如何改进这种网络的论文。其中,采用最广泛的技术被称为 CSMA/CD。它主要用于有线网络,并且被用于以太网。

提高性能的想法:

  1. 载波侦听:在发送前先监听活动,检查是否有其他人正在发送。
  2. 碰撞检测:尝试快速检测碰撞并停止传输,以减少时间浪费。
  3. 随机后退:在碰撞发生后,选择一个基于负载的随机等待时间再重试。

这自然使我们从简单的 ALOHA 机制过渡到广泛使用的 CSMA/CD 协议。


CSMA/CD 协议详解

CSMA/CD 用于原始 10 兆比特每秒以太网。所有主机都可以在同一通道(共享介质)上发送和接收。数据包的大小是可变的。

以下是 CSMA/CD 的工作流程:

  1. 载波侦听:当主机有包要发送时,首先检查线路在传输前是否安静(监听)。如果电线安静,则尝试发送。
  2. 发送与碰撞检测:开始发送数据包,并持续监听线路。
  3. 碰撞处理:如果检测到碰撞,立即停止传输。
  4. 随机后退:等待一个随机的时间。
  5. 重试:回到步骤 1(载波侦听),重新尝试传输。此过程会一直重复,直到成功。

这个随机等待时间被称为二进制指数后退。它意味着随着给定包的碰撞次数增加,等待的时间也会指数级增加。如果存在太多的碰撞,意味着有许多其他传输者,因此应该等待更长时间,以便每个人都有机会发送。


CSMA/CD 工作实例与最小包长要求

让我们看看 CSMA/CD 在实际中如何工作。假设主机 A 有一个包要发送给主机 D。A 会先监听线路。如果线路空闲,A 开始发送数据包。数据包的比特会以光速沿着电缆传播。

在此期间,线路正忙,所以其他主机(B、C、D)都会听到线路正忙,不会尝试发送包。

现在考虑导致碰撞的条件。如果 A 在向 D 发送包的同时,D 也恰好开始向 A 发送包(D 在 A 的包第一个比特到达前的一小段时间监听,发现线路空闲),那么两个包的前端会在电缆中某处相遇并发生碰撞。碰撞信号会向两端传播,最终被 A 和 D 检测到。

CSMA/CD 网络有一个最小包大小要求。原因是为了确保发送方在停止传输自己的包之前,能够可靠地检测到可能发生的碰撞

考虑最坏情况:两个相距最远的主机(A 和 D)几乎同时开始发送。A 发送的包需要时间 L/C(距离除以传播速度)到达 D。如果 D 在 A 的包到达前的一瞬间开始发送,碰撞几乎立即在 D 附*发生。碰撞信号又需要 L/C 的时间传回 A。因此,从 A 开始发送到它可能听到碰撞,最长时间是 2L/C

如果 A 的包太短,在 2L/C 时间内就发送完了,那么即使发生了碰撞,A 在发送完成后才听到碰撞信号,它就无法停止自己的传输,也意识不到是自己的包导致了碰撞。

因此,为了保证可靠碰撞检测,要求:
数据包传输时间 ≥ 信号往返最长时间

用公式表示:
P/R ≥ 2L/C
其中:

  • P = 数据包长度(比特)
  • R = 网络传输速率(比特/秒)
  • L = 网络最大长度(米)
  • C = 信号在介质中的传播速度(米/秒)

例子:假设一个 CSMA/CD 网络运行速率为 10 Mbps(R = 10^7 bps),最大长度为 10,000 米(L = 10^4 m),传播速度是 2 × 10^8 m/sC = 2 × 10^8)。
计算最小包长 P
P ≥ R × (2L/C) = 10^7 × (2 × 10^4 / 2 × 10^8) = 10^7 × (10^{-4}) = 1000 bits
所以,最小数据包大小必须为 1000 位,或大约 128 字节。


总结

本节课中我们一起学习了介质访问控制(MAC)协议的基本原理。

  1. 我们首先了解了共享介质的概念以及协调访问的必要性。
  2. 我们从最简单的随机访问协议 ALOHA 开始,理解了其简单性以及在重负载下性能低下的问题。
  3. 然后,我们深入学习了以太网的核心机制——载波侦听多路访问/碰撞检测(CSMA/CD)。我们详细分析了其“先听后发、边发边听、碰撞停止、延迟重发”的工作流程,以及关键的二进制指数后退算法。
  4. 最后,我们探讨了 CSMA/CD 网络的一个重要设计约束:最小包长要求P/R ≥ 2L/C),以确保发送方能在传输结束前检测到碰撞。

总的来说,我们已经看到了介质访问控制协议是如何从简单的 ALOHA 发展出性能更好的 CSMA/CD。CSMA/CD 是一种简单而有效的随机访问机制,它通过载波侦听和碰撞检测显著提高了共享介质的利用率。在下一个视频中,我们将看到原始以太网如何使用 CSMA/CD,以及以太网如何随时间演变。

posted @ 2026-02-05 08:54  绝不原创的飞龙  阅读(0)  评论(0)    收藏  举报