计算机网络-自顶向下方法笔记-全-

计算机网络:自顶向下方法笔记(全)

1.1:引言 - 什么是互联网 🌐

在本节课中,我们将开启计算机网络的学习之旅。本节是第一章的第一部分,我们将首先对即将学习的内容进行一个宏观概述,然后直接切入核心,探讨两个基本问题:什么是互联网?什么是协议?

课程概述

上一段我们提到了本节的目标,本节中我们将具体介绍本章的覆盖范围。本章内容对应于教材的第一章,我们将从引言开始,探讨上述两个核心问题。随后,我们将深入细节,从网络的边缘开始,逐步深入到网络的核心。

以下是本章将要学习的主要内容列表:

  • 网络边缘:我们将详细查看构成互联网的主机、接入网络和物理介质。
  • 网络核心:我们将探讨构建网络的两种关键技术:电路交换(传统电话网络使用)和分组交换(互联网的技术基础)。我们将讨论分组交换网络中的分组路由器交换机,并分析网络的结构,特别是理解“互联网是网络的网络”这一说法的含义。
  • 网络性能:我们将了解分组在从源到目的地转发过程中如何可能丢失或延迟,并将吞吐量(比特从源到目的地转发的速率)作为一个性能指标进行讨论。
  • 协议分层:这是一种将像互联网这样极其复杂的系统分解和结构化讨论的方法,使其成为更易于管理的部分。
  • 服务模型:我们将讨论网络提供的服务模型。
  • 网络安全与历史:我们将简要介绍网络安全以及计算机网络的历史(其起源远早于互联网的出现)。

以上就是我们的学习路线图。

什么是互联网?🤔

接下来,让我们问自己一个看似简单的问题:究竟什么是互联网?当然,答案很大程度上取决于你问的是谁。

我们可以从工程视角来看待这个问题,这里有两种主要的观点。

视角一:具体构成(螺母与螺栓)

第一种观点非常具体,关注互联网的组成部分。让我们从网络的边缘开始,逐步向内探索。

在网络的边缘,是我们这些互联网用户用来连接互联网的设备。连接到互联网的设备有数十亿之多,我们通常称这些设备为主机端系统。设备的类型繁多,例如:

  • 计算机(个人电脑、数据中心服务器)、智能手机。
  • 家庭中的互联网连接游戏和媒体流设备。
  • 数字个人助理、安全摄像头、能源监视器。
  • 冰箱、洗衣机、烘干机、相框等家用电器,甚至你的床垫。
  • 个人健康和健身设备,以及增强现实/虚拟现实眼镜等人机增强设备。
  • 汽车、卡车、滑板车和自行车等交通工具。

任何数字设备连接到互联网都可能产生价值,而给传统模拟设备(如自行车)赋予数字足迹和互联网连接能力,则能催生新的应用类型。

向网络深处移动,我们找到了使网络真正成为网络的设备,即分组交换机,它们在彼此之间以及在主机和端设备之间转发数据块(分组)。我们将学习两种主要的分组交换机:路由器交换机

此外,还有无数的通信链路将路由器、交换机、主机和端系统互连起来。

最后,这些链路、路由器、交换机、主机和端设备被组装成一个个网络,每个网络都由某个实体拥有和运营。例如,麻省大学校园运营着自己的校园网络,这个网络与连接其他校园网络的互联网骨干网是不同的。正是这些多个网络的存在,才有了“互联网是网络的网络”这一说法。

在本课程中,我们将反复看到,路由器、交换机、主机和端设备之间信息的发送和接收都由协议控制。网络中发生的一切都受协议支配,协议无处不在。因此,这既是一门关于网络原理和实践的课程,也是一门关于协议的课程。

由于协议描述的是做事的标准方式,因此需要一个机构来为互联网定义这些标准。这个定义互联网标准和协议的组织被称为互联网工程任务组,其标准文件被称为RFC

视角二:服务平台

第二种回答“什么是互联网”的方式是从服务的角度出发,将互联网视为一个可以运行所有精彩应用的平台

作为一个服务平台,互联网提供了一个接口,应用程序可以利用这个接口相互发送和接收信息。从服务视角来看,互联网的核心就是将信息从网络中的一个点传送到另一个点

那些位于网络端点的互联网应用可能极其复杂和精密。但所有这些应用层的复杂性都建立在基本服务基础设施之上,该设施的核心任务只是简单地将分组从一个位置传送到另一个位置。

什么是协议?🤝

前面我们提到互联网的核心是协议,那么什么是互联网协议呢?理解互联网协议最简单的方法之一是先思考人类协议。人类一直在执行协议。

例如,考虑一个“现在几点”的协议:

  1. 一个人说:“打扰一下,你知道现在几点吗?”(请求)
  2. 第二个人看看手表,回答:“两点十分。”(响应)

再比如课堂上的“提问”协议:

  1. 教授问:“有什么问题吗?”
  2. 学生可能低头看笔记,或者举手。
  3. 如果学生举手,教授说:“好的,请讲。”
  4. 学生提问,教授回答。

从这些人类协议中,我们可以看到共同点:有特定的消息被发送(人类说出的话),并且当对方收到这些消息时,会采取特定的行动

计算机网络协议与这些人类协议完全类似,只不过交换消息和采取行动的主体变成了网络组件(应用程序、主机、路由器、交换机、链路等)。

以人类的“现在几点”协议为例,它有两个不同的阶段:问候阶段(“打扰一下”)和请求-响应阶段。我们很快会看到,这与Web上使用的协议(如HTTP)完全类似:先有一个连接建立阶段,然后是请求-响应阶段。

基于以上背景,我们可以为网络协议下一个实用的定义:

协议定义了网络实体之间发送和接收的消息的格式和顺序,以及在消息传输和接收时采取的动作

总结与预告

本节课中,我们一起学习了两个技术要点:我们探讨了“什么是互联网”这个问题(从边缘到核心的构成视角以及服务平台视角),并讨论了“什么是协议”这个概念。

在下一节中,我们将更深入地采用“具体构成”的视角来回答“什么是互联网”这个问题。我们将从之前简要提及的网络边缘设备开始,然后逐步向网络内部探索。

1.2:网络边缘

概述

在本节课中,我们将学习计算机网络中的“网络边缘”。我们将探讨连接终端设备到互联网的“接入网络”,以及用于传输比特的“物理介质”。理解这些概念是理解整个网络如何工作的基础。


网络边缘回顾

上一节视频中,我们介绍了网络边缘的各种设备,如计算机、智能手机和家用设备。这些设备有时被称为“主机”,因为它们承载或运行网络应用程序。主机可以是请求服务的“客户端”,也可以是提供服务的“服务器”。在第二章中,我们将看到客户端和服务器在网络上下文中的精确定义。

上一节我们还简要提到了接入网络和物理介质,这正是本节要重点讨论的内容。此外,我们也谈到了由互连路由器构成的“网络核心”,以及这些独立的、有管理范围的网络如何互连形成“互联网”。以上就是我们开始讨论的大背景。


接入网络

本节中,我们来看看接入网络。接入网络是将终端系统(主机或设备)连接到更大的全球互联网的网络。它本质上是将设备连接到从源到目的路径上的“第一跳路由器”的网络。接入网络主要有三种类型:

  • 住宅接入网络:连接家庭到互联网。
  • 机构接入网络:由公司、教育机构或市政当局运营。
  • 移动接入网络:由蜂窝网络运营商和Wi-Fi网络运营。

在讨论这三种接入网络时,你可以关注两个关键点:

  1. 该接入网络的比特传输速率是多少?(即网络速度有多快?)
  2. 用户需要在多大程度上与其他用户共享该网络?

住宅接入网络:有线电视网络

让我们从最贴近生活的住宅接入网络开始讨论,首先看看有线电视网络

如下图所示,在有线电视接入网络中,一条物理电缆将多个家庭连接到一个位于右侧的“电缆头端”。进出这些家庭的信号以不同频率在电缆上发送。以不同频率发送的信号不会相互干扰,这类似于FM广播电台在不同频率上发射信号,我们则调谐到想要的频率。有线电视接入网络基于相同的方法,称为频分复用

但频率资源是有限的,因此有线电视用户通常需要与邻居共享一个频率。我们将在第6章详细讨论有线电视接入网络及其DOCSIS标准。现在,请先理解这个核心概念,细节留待以后学习。

有线电视网络通常是不对称的,这意味着它们被设计为在“下行”(到家庭)方向传输数据比“上行”(从家庭)方向更快。这种不对称性反映了我们往往是数据的消费者多于生产者的事实。

典型的有线电视传输速率在下行方向为40 Mbps至1.2 Gbps,上行方向为30至100 Mbps。当然,实际速率可能因情况而异,你的调制解调器通常会根据你购买的服务套餐进行速率限制。

再次注意,有线电视网络是一个共享网络。它本质上就是一根共享的线缆(通常架设在电线杆上)。这意味着如果你和你的邻居共享一根电缆上的一个频率,而你的邻居正在大量收发数据,这可能会影响你能够发送和接收的数据量。


住宅接入网络:数字用户线路

第二种主要的住宅接入类型是数字用户线路

DSL网络使用现有的电话线(有时称为“双绞线”,因为有两根铜线缠绕在一起)将你直接连接到所谓的“中心局”。因此,在你和中心局之间,你与邻居共享传输容量或带宽。

与有线电视网络一样,DSL线路也是不对称的,下行传输速率为24至52 Mbps,上行传输速率为3.5至16 Mbps。这些传输速率在很大程度上取决于中心局与你家之间的距离。事实上,如果距离太远(通常超过约3英里),就无法使用DSL连接到中心局。


家庭网络内部

现在让我们看看家庭内部。一个典型的家庭网络可能如下图所示。

来自本地电话公司或有线电视网络的DSL或有线电视链路进入家庭。在链路家庭端有一个电缆或DSL调制解调器,它连接到一个兼具有线和无线功能的路由器。路由器通过有线以太网(通常运行在100 Mbps或1 Gbps)和Wi-Fi(运行在数十或数百Mbps)与家庭内的设备连接。通常,路由器、调制解调器、Wi-Fi和以太网功能都集成在一个设备中。当然,还有我们之前讨论的家庭设备本身,即主机和终端系统。


无线网络

既然我们已经在家庭网络的背景下提到了Wi-Fi网络,让我们先来看看无线网络。整个第7章都将专门讨论无线网络,所以这里我们只了解其概貌。

一种思考方式是,无线网络基本上分为两大类:

  1. 本地无线网络,例如Wi-Fi。
  2. 广域网络,对应于3G、4G以及即将到来的5G蜂窝网络。

对于本地无线网络和数字蜂窝网络,都有一个实体——基站接入点,终端设备通过它发送和接收数据。

以下是两种主要无线网络的对比:

  • Wi-Fi网络

    • 也称为无线局域网。
    • 不仅用于家庭,也广泛部署于市政、公司和其他机构。
    • 覆盖范围约10至100米。
    • 运行速度从11、54到450 Mbps不等。
    • 由IEEE在802.11协议族下标准化。
  • 蜂窝网络

    • 指3G、4G和即将到来的5G网络。
    • 由移动蜂窝运营商运营。
    • 覆盖范围可达数十公里。
    • 每个用户的传输速率从1-10 Mbps到数十Mbps不等。

企业网络

最后,还有企业网络。我们可以把一些企业网络看作是“加强版”的家庭网络。企业网络可能混合使用有线以太网和无线Wi-Fi链路。与家庭网络的一个不同之处是,企业网络通常有多个交换机和路由器来处理连接到该网络的大量设备。

另一种完全不像家庭网络的企业网络是数据中心网络,它以数百Gbps的速度将大量服务器相互连接并连接到互联网。我们将在第6章详细讨论数据中心网络。

关于接入网络,我们就先讲到这里。我们将在第6章和第7章中再回来详细讨论。现在,你可能想思考一下我们一直在谈论的物理介质——铜线、光纤和无线电链路。我们马上就会讲到这些。


数据包的概念

但首先,我想简单说一下“数据包”。我使用了“数据包”这个短语,我们也讨论了发送方如何将数据包发送到接入网络。这到底是什么意思?

让我们看看这里的主机,它正在向这里的第一个交换机发送数据。考虑它的发送操作:在最高层面,主机有一些想要发送的数据,比如一个大文件。主机会怎么做?

主机会将要发送的数据分割成更小的数据块,称为数据包。除了数据本身,它还会在每个数据块上添加一些额外信息,称为数据包首部。协议会明确规定在这个首部中添加什么信息。一个数据包(数据加首部)的长度为L比特,L的典型值可能是1500字节。

然后,主机以某个传输速率R(以比特/秒为单位)将这个L比特的数据包发送到接入网络中。正如我们已经看到的,R因接入网络类型而异。我们看到,使用有线以太网,主机可以以1 Gbps的速度发送,但在3G或4G网络上,它可能被限制在几Mbps或更低。R最好被视为链路传输速率,但有时更非正式地称为链路容量或链路带宽。

如果要以传输速率R向链路发送一个L比特的数据包,那么将这些比特发送到链路中所花费的时间就是发送的比特数L除以传输速率R。我们稍后会再回到这个概念。


物理介质

我们将通过快速了解不同传输介质的物理特性来结束本节。但在这样做之前,我想简单说明一下我们在这里的覆盖深度。

关于调制、编码以及与比特物理传输相关的内容,有很多有趣的话题可以讨论,但一门课程能容纳的内容有限。因此,在这里我们将相当简要地介绍。如果这类内容让你非常兴奋,想了解更多,你绝对应该选修另一门课程或阅读另一本相关的书籍。

我们将从一个相当高的层面来看待不同传输介质的物理特性。我们将关注比特丢失特性、信号如何干扰、传播延迟是怎样的,但不会深入探讨不同物理传输介质的工作原理细节。如果你想深入了解,请查阅更多资料。这当然是一个关于网络的问题,我们将从这里开始,逐步深入。

以下是一些关于物理介质的基本事实。记住,我们想要做的是通过某种物理介质从发送方到接收方发送数字比特。

物理介质可以是导引型介质,即某种物理电线或电缆(可能由铜或光纤制成);也可以是非导引型介质,信号在其中自由传播,如无线电波或声波。

以下是几种常见物理介质的对比:

  • 双绞线

    • 过去指真正缠绕在一起、为你祖父母家传送电话信号的电线。
    • 现在也指以太网或ADSL,运行在数百Mbps,有时可达Gbps。
    • 可能易受电磁噪声干扰。
    • 你可能在家、办公室或学校见过这样的以太网电缆。
  • 同轴电缆

    • 过去用于将有线电视网络接入你家,运行在数百Mbps。
    • 老式以太网实际上曾使用这样的电缆运行,但至少20年前就不再使用了。
  • 光纤

    • 传输光脉冲,运行在数百Gbps或更高速度。
    • 误码率非常低,因此在某种意义上,它们是通信的理想选择。
    • 但发射和接收组件往往比传统铜线的更昂贵。
  • 无线链路

    • 比特被调制到电磁频谱某个频段承载的信号上。
    • 没有物理电线,传输往往是广播的,意味着发射设备附近的任何设备都可能接收到发射的信号。这显然引发了窃听和干扰问题。
    • 无线环境对传输无线电信号来说 notoriously harsh:信号随距离衰减;根据频率不同,信号可能被物体反射或阻挡,或者在其他频率下直接穿透墙壁等物体。
    • 它们容易受到电机、微波炉和其他发射RF信号的设备产生的噪声影响。
    • 因此,通过无线传输比特需要在物理层做大量工作,这就是为什么有整门课程专门讨论这个主题。

你可能熟悉多种类型的无线链路。我们已经讨论过Wi-Fi网络,它可以以高达数百Mbps的速度传输,距离可能为数十米。4G蜂窝网络以数十Mbps的速率传输数据,距离可达约10英里。你们中的许多人可能使用蓝牙,它被用作电缆替代技术,以相对较低的数据速率(例如最大1或2 Mbps)运行,覆盖范围相对较短,通常不超过5或10米。

还有其他形式的无线网络,例如地面微波,以数十Mbps的点对点方式运行。卫星的传输速率大致相同。对于卫星,存在明显的传播延迟(即比特从发送方发送到接收方接收的时间)。在发送方/接收方与地球同步卫星之间,有明显的270毫秒传播延迟。


总结

本节课我们一起学习了网络边缘的核心组成部分。我们探讨了连接终端设备到互联网的三种主要接入网络(住宅、机构和移动),并了解了数据包的基本概念。我们还简要介绍了各种物理传输介质(双绞线、同轴电缆、光纤和无线链路)的特性及其典型应用场景。这些知识为我们理解数据如何从网络边缘开始其旅程奠定了基础。接下来,我们将深入网络核心,探索数据在互联网主干中是如何被路由和转发的。

1.3:网络核心 🌐

在本节中,我们将概述网络核心。我们将了解网络核心内部发生了什么,并介绍一系列重要主题。我们将讨论分组转发、分组排队时延和分组丢失。我们将讨论分组交换的替代方案——电路交换,并探讨互联网的结构,理解“互联网是网络的网络”这一说法的含义。

网络核心由一组通过通信链路互连的路由器构成。互联网核心的运作基于一个称为分组交换的原则,其原理相对简单。其思想如下:之前讨论的端系统将应用层报文分割成数据块,将这些数据块放入分组中,然后将这些分组发送到互联网中。这些分组随后沿着从源节点到目的节点的路径被转发,例如,从一台Web服务器转发到运行着Web浏览器并发出请求的笔记本电脑。

让我们稍微拆解一下最后这句话,因为其中包含了许多重要的概念。我们谈到了转发,谈到了从源到目的的路径,也谈到了目的。在网络核心内部执行着两个关键功能:转发(有时也称为交换)和路由

让我们深入路由器内部,看看这些功能是什么。

转发与路由 🔄

转发是一个本地动作。它指的是将到达的分组从路由器的输入链路移动到适当的输出链路。转发由我们在此看到的转发表控制。互联网中数以百万计的路由器,每一个内部都有一张转发表。当一个分组到达时,路由器会查看分组内部的目的地址,然后在其转发表中查找该目的地址,如这里所示。接着,路由器会将该到达分组传输到通往该目的地的输出链路上。从概念上讲,这很简单:查找并转发。但你可能想知道,这些转发表的内容最初是如何创建的呢?这就引出了网络核心的第二个关键功能:路由

路由是确定分组从源到目的所走路径的全局动作。正如我们将看到的,路由算法计算这些路径,并计算实现这种端到端转发路径所需的、每个路由器本地的转发表。

理解转发和路由区别的一个很好的类比是开车旅行。我最近从加利福尼亚州的圣何塞一路开车到东海岸的马萨诸塞州北安普顿,这是一次长途旅行。我决定选择上面这条路线,而不是下面这条。这就是路由决策,决定了从源(加利福尼亚州圣何塞)到目的地(马萨诸塞州北安普顿)所走的路径。现在,当我到达一个交汇处,比如加利福尼亚州的萨克拉门托时,我正从一条输入道路进入城市,需要被转发到一条输出道路上。实际上,沿途的所有交叉路口,从输入道路切换到输出道路就是本地转发功能,而全局路由功能则决定了我实际上被转发到哪条输出道路上。你可能想稍微思考一下本地转发功能和全局路由功能之间的关系。你能想到其他类比吗?

接下来,让我们关注网络核心中路由器上分组比特的传输。

存储转发与排队时延 ⏳

在这张图中,我们展示了一个分组中的比特从一个路由器传输到下一个路由器。希望你还记得,如果一个分组的长度为 L 比特,链路传输速率为 R 比特/秒,那么将分组传输到链路上需要 L / R 秒。传输的比特将在链路的接收端被接收并汇集起来,直到整个分组被接收完毕。你可以看到分组中的比特在这里被汇集。一旦分组被完全接收,它就可以被转发到下一跳,依此类推。这就是所谓的分组交换网络的存储转发操作。

现在,让我们更仔细地看看分组到达路由器等待转发时会发生什么。

在这张图中,我们看到一个有三条链路的路由器。假设主机A正在向主机C发送分组,主机B正在向主机E发送分组。现在让我们仔细看看输入链路的速率。从A到第一跳路由器的链路传输速率 R 是100 Mbps,从B到第一跳路由器的第二条链路也是如此。但是,从第一跳路由器到第二跳路由器的链路传输速率只有1.5 Mbps,慢了近100倍。这在家庭网络中并不少见,家庭网络路由器可能连接着运行在千兆比特每秒的家庭以太网或54 Mbps的Wi-Fi,但连接到电缆调制解调器头端的接入链路要慢得多,可能只有5或10 Mbps。那么问题来了:当分组到达这个第一跳路由器时会发生什么?

在这个例子中,路由器只能以1.5 Mbps的速度传输,而如果A和B同时发送大量分组,分组的到达速率肯定可以远高于1.5 Mbps。如果太多分组以过快的速率到达,那么如该图所示,在第一跳路由器中就会形成一个分组队列。

每当工作到达的速度超过某个服务设施实际服务该工作的速度时,就会发生排队。当然,我们都熟悉排队。这是等待在收费站接受服务的汽车队列。我们在商店的收银台排队,我想你们很多人也曾在财务处排队缴费。这是一群人在建筑物外排队等候,这是一群在英国排队的人——如果你去过英国,你可能知道“queuing”是英国人用来表示“排队”的词,英国人非常擅长排队。

回到网络,当输入链路上的比特到达速率(比特/秒)在一段时间内超过输出链路的传输速率(比特/秒)时,分组队列就会在路由器的出站链路上形成。当存在分组队列时,就会产生排队时延,分组必须在路由器中等待,而不是被转发到目的地。由于路由器中用于存储排队分组的内存有限,如果队列变得太长,路由器的内存耗尽,到达的分组可能会发现没有内存可供存储。在这种情况下,分组将在该路由器被丢弃丢失。正如我们将看到的,分组可能被延迟和/或丢失这一事实,将成为许多网络协议的主要难题来源。

到目前为止,我们一直在讨论分组交换,并且刚刚看到,由于网络并不总是足够仔细地控制发送方以确保不会发生大的排队时延和分组丢失,所以分组排队时延和分组丢失可能会发生。

电路交换 ⚡

分组交换并不是构建网络的唯一方式。事实上,在互联网出现之前很久,在分组交换出现之前很久,电话网络就采用了一种不同形式的技术,称为电路交换。让我们来看看电路交换。

在电路交换中,存在呼叫的概念,而不是从源到目的流动的分组概念。在呼叫开始之前,网络中该呼叫所需的所有资源都从源到目的地分配给该呼叫。因此,一旦呼叫开始,呼叫就为自己预留了足够的传输容量,以确保永远不会发生排队。除了传播时延外没有其他时延,并且由于链路容量已为此呼叫专用而保留,网络内部没有数据丢失。

在此图中,每条链路有四个电路。从左上方到右下方的呼叫被分配了顶部链路上的第二个电路和右侧链路上的第一个电路。这些电路是专用资源,不与其他任何用户共享。这就像从源到目的地有一条专用线路。这一切听起来很不错:没有时延,没有丢失,再好不过了。直到你开始思考这样一个事实:由于资源是为呼叫专用而保留的,如果该呼叫没有数据传输,电路就会闲置。这就是问题所在。如果带宽没有被呼叫使用,它就浪费了,其他任何呼叫都无法使用它。因此,正如我们马上将看到的,电路交换网络可能效率低下。

电路交换通过两种方式之一实现:频分复用时分复用。在FDM中,电磁或光频谱被划分为窄频带,每个呼叫被分配其中一个窄频带,并可以以该频带允许的全速率传输。在TDM中,时间被划分为时隙,每个呼叫被分配一组周期性的时隙。源只能在分配的时隙内传输,但可以以更宽频带的更高最大速率进行传输。

分组交换与电路交换:性能对比 📊

既然我们已经介绍了电路交换和分组交换的概念,让我们看一个数值例子,来了解在特定网络场景下可以支持的用户数量。

这是一个我们想要查看的场景。假设我们有一条1 Gbps的链路。有终端用户,每个用户的行为如下:当他们有数据要发送时,他们需要以100 Mbps的速度发送,这是总链路带宽的十分之一。然而,用户只有10%的时间处于忙碌状态。这意味着90%的时间他们没有数据要发送。让我们看一个数值例子,看看在这个网络设置下可以支持多少分组交换用户和多少电路交换用户。

假设用户数 N 为35。对于电路交换的情况,计算很简单。在电路交换下,每个用户需要100 Mbps,因此电路交换网络最多可以同时支持10个用户。

现在让我们看看分组交换。记住,每个用户需要100 Mbps,所以我们可以支持10个分组交换用户,就像我们可以支持10个电路交换用户一样,没问题。但请记住,每个用户只有10%的时间处于忙碌状态。如果我们允许所有35个用户进入系统,会发生什么?在给定时间,超过10个用户处于活动状态的概率是多少?只有当超过10个用户处于活动状态时,队列才会形成并增长。通过一些基本的概率和组合数学(本课程不要求,因此我们不在此深入计算)可以证明,在35个用户中,超过10个处于活动状态的时间比例是0.0004。也就是说,如果在分组交换下我们允许所有35个用户进入系统,那么队列开始增长的时间百分比不到时间的0.04%。这是一个非常小的数字。也许我们愿意忍受偶尔的时延和丢失,以允许所有35个用户(而不仅仅是10个)进入系统。分组交换下的这种性能增益被称为分组交换的统计复用增益,这是60年前分组交换发明时支持使用分组交换的一个关键论点。

互联网:网络的网络 🌍

现在,你可能觉得分组交换简直是天赐之物。它是否已是毫无悬念的赢家?看起来似乎是,甚至今天的电话网络实际上也以分组形式承载数据,所以在某种意义上,我们可以宣布分组交换获胜。分组交换特别适合突发性数据,即源只是偶尔有数据要发送的情况。它很简单:没有呼叫建立,没有资源预留。主机只是开始发送它需要发送的数据。我们已经看到拥塞、分组时延和丢失可能发生,但我们也将看到,互联网协议(特别是TCP)将通过在面对拥塞时降低发送方的发送速率来对拥塞做出反应。因此,拥塞和丢失在某种意义上是可以避免或至少减轻的。是否可能用分组交换提供类似电路的行为?嗯,俗话说,这很复杂,但我们将研究各种试图尽可能接近电路行为的技术。

让我们通过回到我提到过几次的一个短语来结束对网络核心的介绍:互联网是网络的网络。这到底是什么意思?这又是如何实际反映在互联网结构中的?

到目前为止我们看到的是,网络边缘的用户连接到接入网络,无论是家庭网络、移动网络还是机构网络。我们需要某种方式将这数百万个接入网络彼此连接起来,以在用户之间获得端到端路径。我们该怎么做呢?我们可以将每个接入ISP连接到其他每一个接入ISP,但这将需要大约 个连接,当N达到数百万时,这种方法无法扩展。因此,考虑到有数百万个接入ISP,我们可能会创建一个全球性的中转ISP。每个边缘的ISP然后连接到这个全球中转网络(你可以称之为骨干网),一个接入ISP将通过这个骨干网到达另一个接入ISP。在计算机网络的早期,边缘网络确实是这样互连的。但是,当然,如果一个全球ISP是一个可行的业务,就会出现骨干网服务的竞争者,这些全球骨干网需要彼此互连。我们说一个网络与另一个网络对等,当它们直接互连时。多个网络可以彼此对等的位置有时被称为互联网交换点对等点

区域网络可能会形成,以互连更靠近本地的接入网络,并连接到全球骨干网。例如,纽约州的NYSERNet(纽约州教育与研究网络)就是一个区域网络的例子,它为大学、学院、博物馆、医疗机构和K-12学校提供互联网接入。然后,像谷歌、微软、亚马逊、Akamai这样的内容提供商可能希望运行自己的全球网络(事实上他们确实这样做了),以便将他们的服务和内容带到离终端用户更近的地方。我们在这里看到的这幅图非常接近当今互联网的结构。

我们说过互联网是网络的网络,现在你对这到底是什么意思有了一些概念。在互联网的中心,我们有数量相对较少、连接良好的大型网络。这些有时被称为一级商业ISP,例如Level 3、Sprint、AT&T、NTT,它们拥有全国和国际覆盖范围。更靠近边缘的是区域网络,它们都相互连接(即彼此对等,并与一级提供商对等)。在网络的最边缘则是接入网络本身。当然,还有像谷歌和Facebook这样的内容提供商网络,这些私有网络将他们的数据中心和服务连接到互联网,有时会绕过一级和区域ISP。

为了让你了解一级ISP实际上是什么样子,这里有一张Sprint美国网络的近期地图。你可以看到边缘的各种国际连接。这里显示的每个Sprint节点实际上是一组路由器的集合,它们共同构成了所谓的存在点。这是一个POP的放大图,你可以看到一组将POP路由器连接到客户网络的链路,另一组连接到其他Sprint POP的链路,以及最后一组连接到对等网络(例如其他一级网络)的路由器。

总结 📝

本节课中我们一起学习了网络核心的概述,并介绍了一些非常重要的概念。我们讨论了分组转发过程、存储转发网络、排队时延以及分组丢失的可能性,并区分了分组转发和分组路由。我们还讨论了分组交换网络的替代方案——电路交换网络,并讨论了各自的优缺点。最后,我们探讨了“互联网是网络的网络”这一概念的含义。接下来,我们将研究网络性能。

1.4:网络性能 🚀

在本节课程中,我们将深入学习计算机网络的两个核心性能指标:延迟吞吐量。我们将详细拆解延迟的各个组成部分,学习使用traceroute工具测量实际网络延迟,并理解吞吐量如何受网络链路容量的限制。


延迟的四个组成部分 ⏱️

上一节我们讨论了网络核心中数据包的排队与丢失。本节中,我们将更深入地探讨性能问题,首先从延迟开始。

数据包在路由器中可能经历四种延迟:

  1. 处理延迟
    这是路由器检查数据包首部、决定其转发方向以及进行完整性检查所花费的时间。这些操作通常在微秒或更短时间内完成。

  2. 排队延迟
    这是数据包在输出链路的缓冲区中等待传输所花费的时间。排队延迟的长短取决于该链路的拥塞程度。

  3. 传输延迟
    这是将数据包的所有比特推送到链路上所需的时间。它取决于数据包的长度和链路的传输速率。其计算公式为:
    传输延迟 = L / R
    其中,L是数据包长度(比特),R是链路传输速率(比特/秒)。

  4. 传播延迟
    这是一个比特从链路起点传播到终点所需的时间。它取决于物理介质的长度和信号传播速度(接近光速)。对于长距离链路(如跨洋光缆或卫星链路),传播延迟会非常显著。


传输延迟 vs. 传播延迟 🚗

初学者有时会混淆传输延迟和传播延迟。让我们通过一个类比来区分它们。

想象一个由10辆车组成的车队(数据包)通过两个相距100公里的收费站(路由器)。

  • 传输延迟:类似于收费站为每辆车服务所需的时间。假设每辆车需要12秒,那么整个车队通过第一个收费站需要 10 * 12秒 = 120秒
  • 传播延迟:类似于车辆在高速公路上行驶100公里所需的时间。假设车速为100公里/小时,那么最后一辆车从第一个收费站行驶到第二个收费站需要 100公里 / 100公里/小时 = 1小时

因此,整个车队在第二个收费站前集结完毕的总时间是 传输延迟(2分钟) + 传播延迟(60分钟) = 62分钟


深入理解排队延迟 📊

了解了传播延迟后,我们再来定量地分析排队延迟。

定义:

  • a = 数据包平均到达速率(包/秒)
  • L = 数据包长度(比特/包)
  • R = 链路传输速率(比特/秒)

那么,到达链路的比特率为 L * a。我们引入一个关键指标——流量强度
流量强度 = (L * a) / R

流量强度直观地反映了系统负载:

  • 流量强度 → 0 时,排队很少发生。
  • 流量强度 → 1 时,平均到达的工作量接近系统处理能力,排队延迟会急剧增加。
  • 流量强度 > 1 时,到达的工作量持续超过处理能力,队列将无限增长,延迟趋于无穷大。

这类似于道路拥堵:当车流量接近道路容量时,通行时间会迅速增加。


使用 Traceroute 测量实际延迟 🔍

本课程中,我们将使用真实的互联网来阐释所学原理。traceroute 就是一个可以测量从源主机到目的主机路径上各节点延迟的工具。

traceroute 的工作原理如下:

  1. 首先向路径上的第一跳路由器发送三个探测数据包。
  2. 该路由器回复响应消息。
  3. 发送端测量从发出探测包到收到回复的往返时间,并显示这三个RTT值。
  4. 接着向第二跳路由器发送三个探测包,测量并显示RTT。
  5. 重复此过程,直到到达最终目的地。

以下是一个从美国马萨诸塞州到法国服务器的 traceroute 输出示例片段:

1   cs-gw (128.119.240.254)  1 ms  1 ms  2 ms
2   * * *
3   dc-rtr (192.168.1.1)      22 ms 22 ms 22 ms
4   fr-rtr (193.55.144.1)     105 ms 106 ms 105 ms
  • 第1跳在本地网络,延迟约1-2毫秒。
  • 第3跳到达华盛顿特区,延迟约22毫秒。
  • 第4跳进入法国,延迟跃升至105毫秒,这体现了横跨大西洋的传播延迟
  • 有时会出现 *,表示该路由器未回复探测包。
  • RTT可能因网络拥塞(排队延迟)变化而波动,即使数据包传得更远,延迟也可能降低。

数据包丢失 📦

除了延迟,我们还需记住,在高拥塞情况下,当路由器缓冲区被填满时,会发生数据包丢失。丢失率有时可能高达10%-20%。在后续第3章,我们将学习主机如何检测和从丢包中恢复,以及如何控制发送速率以管理拥塞。


吞吐量 🌊

我们要讨论的最后一个性能指标是吞吐量,即从发送方到接收方传输数据的速率(比特/秒)。

理解吞吐量时,一个有用的类比是水流过一系列管道:

  • 发送方以某种速率向管道注入流体(数据)。
  • 路径上的每条传输链路就像一根有特定容量的管道(有的粗,有的细)。

关键问题是:当端到端流经过一系列串联的管道时,整体吞吐量受限于哪根管道?

请看以下两个场景:

  1. 场景一:一个细管道(容量 R_s)后接一个粗管道(容量 R_c,且 R_c > R_s)。
    • 端到端吞吐量受限于细管道的容量 R_s
  2. 场景二:一个粗管道(容量 R_s)后接一个细管道(容量 R_c,且 R_c < R_s)。
    • 端到端吞吐量受限于细管道的容量 R_c

结论:端到端路径的吞吐量受限于路径上容量最小的链路,即瓶颈链路


多流共享与吞吐量 🤝

最后,我们需要考虑网络中多个数据流如何交互并影响各自的吞吐量。

假设有10台服务器和10台客户端,每对之间建立一个连接。网络边缘的链路是专用的,但网络中心有一条共享链路,容量为 R,并且该链路能公平地在10个流之间分配带宽。

那么,每个连接将经过三段“管道”:容量为 R_s 的接入链路、共享的 R/10 核心链路、容量为 R_c 的接入链路。

因此,每个连接的端到端吞吐量将是这三个值中的最小值:min(R_s, R_c, R/10)。在实践中,通常 R_sR_c(边缘链路)会小于 R/10,这意味着瓶颈链路往往位于网络边缘。


总结 📝

本节课中,我们一起深入学习了网络性能的两个关键方面:延迟和吞吐量。

  • 在延迟部分,我们明确了其四个组成部分:处理延迟排队延迟传输延迟传播延迟,并使用 traceroute 工具观察了互联网中的实际延迟。
  • 在吞吐量部分,我们借助流体与管道的类比,理解了端到端吞吐量受限于路径上的瓶颈链路,并探讨了多流共享场景下的吞吐量计算。

希望这些知识能帮助你更好地理解和分析网络性能。

1.5:分层与封装 🏗️

在本节中,我们将学习如何理解和描述极其复杂的互联网系统。我们将介绍分层架构的概念,审视互联网的五层模型,并精确地定义数据在网络中流动时的形态——数据包。通过理解封装过程,你将能清晰地看到数据从发送方应用层到接收方应用层的完整旅程。

分层架构的概念

互联网是一个由数十亿交互部件组成的庞大系统,包括应用、设备、链路、路由器、交换机等。为了应对这种复杂性,我们采用分层架构来设计、讨论和教学。

我们可以用一个类比来理解分层:航空旅行系统。这个系统非常复杂,涉及购票、值机、安检、登机、飞行、行李托运等多个环节。我们可以将这些环节视为一系列水平层的功能。例如,“值机”功能在出发机场和到达机场共同协作,为你提供“旅客登记”服务。为了实现这个服务,它依赖于“行李处理”和“安检”等下层服务。

这种分层思考方式有两个主要优势:

  1. 提供清晰的参考模型:它明确了系统的不同部分及其相互关系,便于我们讨论系统。
  2. 实现模块化设计:每一层都使用下层提供的服务来实现自己的服务,并向上层提供服务。只要保持层与层之间的接口不变,修改某一层的实现方式就不会影响其他层,这使得系统的实现和维护更加容易。

互联网的五层模型 🖥️

互联网采用的就是分层架构,具体分为以下五层:

  1. 应用层:包含控制分布式应用程序各部分之间消息收发行为的应用层协议。在本课程中,我们将首先学习这一层。
  2. 传输层:负责在进程之间传输应用层消息。例如,互联网的TCP协议能在可能丢失数据包的网络服务之上,实现可靠的数据传输服务
  3. 网络层:负责将数据从一台主机传输到另一台主机。互联网的网络层提供的是尽力而为服务,不保证可靠性。请注意,主机到主机(网络层)与进程到进程(传输层)的传输范围是不同的。
  4. 链路层:负责在同一通信链路两端的网络设备(如路由器、主机)之间传输数据。
  5. 物理层:负责控制比特在物理链路中的传输。

封装:数据包的旅程 📦

现在,让我们更精确地了解数据是如何在各层之间交换的。这个过程的核心是封装

  • 应用层,交换的数据单元称为报文
  • 传输层,传输层实体会接收应用层报文,并为其添加传输层首部信息(例如,用于标识目标进程的端口号、实现可靠传输的控制信息),从而生成一个新的数据单元,称为报文段。这个添加首部信息的过程就是封装。
  • 网络层,网络层协议封装传输层报文段,添加网络层首部(例如,包含发送和接收主机IP地址),生成数据报
  • 链路层,链路层协议封装网络层数据报,添加链路层首部(和可能的尾部),生成

数据在发送端沿着协议栈向下流动,每经过一层就被封装一次,添加该层的首部。最终,物理层的比特流通过链路传输。

在接收端,数据沿着协议栈向上流动,每经过一层,该层的实体就会读取并处理其对应的首部信息,然后将剩余的数据部分向上传递给下一层。首部信息在逐层处理后被“剥离”。

需要特别注意的是,网络中的路由器、交换机等中间设备通常只实现协议栈的下三层(网络层、链路层、物理层)。它们的任务是转发数据报和帧,无需处理封装在内部的传输层报文段或应用层报文。

总结

在本节中,我们一起学习了三个核心概念:

  1. 分层架构:一种通过将系统划分为多个具有明确定义的服务和接口的层次,来管理复杂性的方法。
  2. 互联网五层模型:应用层、传输层、网络层、链路层和物理层,这为我们理解网络提供了结构框架。
  3. 封装:数据从高层向低层传递时,每层都会添加自己的控制信息(首部)以形成新的协议数据单元(PDU)。这个过程使得数据能够被正确地在网络中传输、寻址和交付。

理解数据如何通过封装在协议栈中上下流动,是掌握计算机网络工作原理的基础。接下来,我们将简要了解网络面临的一些安全威胁。

1.6:网络攻击与防御 🛡️

在本节中,我们将对计算机网络中的安全问题进行一个概览。我们将探讨攻击者可能对网络实施的几种主要攻击方式,并了解可用于防御、缓解和应对这些攻击的广泛技术类别。请在学习后续课程时,始终将这两个核心问题的答案记在心中。

概述

最初的互联网架构在设计时并未将安全性作为核心考量。这并非设计者遗忘了安全,而是其最初的愿景是服务于一个“相互信任的用户群体”,他们连接在一个“透明的网络”上。显然,这与我们今天面临的现实情况大相径庭。设计者并非天真,只是在当时的设想使用场景下,安全性并未被有意识地列为关键设计标准。因此,时至今日,我们仍在某种程度上为网络安全“补课”。

思考网络安全时,我们需要考虑几个方面:

  1. 攻击者如何攻击或破坏计算机网络。
  2. 我们如何防御这些攻击。
  3. 我们如何设计能够抵御攻击的网络架构,这有时被称为“安全设计”。

攻击者的行为方式 🔓

现在,让我们来看看攻击者可能采取的一些行为方式。

首先,一个合理的假设是,攻击者能够获取在共享媒体(例如无线信道)上传输的数据包副本。例如,如果攻击者位于位置C,我们应该假设C能够读取B通过共享媒体发送给A的所有内容。实际上,存在名为“数据包嗅探器”的软件工具可以实现这一点。在本课程中,我们将广泛使用名为Wireshark的嗅探器来捕获网络上的数据包,以便观察协议的实际运行。

其次,我们应该假设攻击者能够向网络中注入包含任意信息的数据包。例如,位于C的攻击者可以向A发送一个伪造的数据包,其源地址被篡改,使A误以为该数据包来自B。这在概念上类似于你收到一封声称来自银行或同事的钓鱼邮件,声称他们获得了一笔巨款,需要你帮忙存入银行账户并分享收益。你不会相信他们。同样,网络设备或软件也不应仅仅因为一个数据包到达了就相信它所声称的内容。

此外,攻击者还可以通过产生巨大的工作负载来发动拒绝服务攻击,使网络设备过载。例如,HTTP服务器可能被大量伪造的HTTP请求轰炸,或者路由器可能被持续涌入的需要转发或特殊处理(如我们之前看到的traceroute数据包)的数据包淹没。这类攻击通常由攻击者入侵互联网上的其他主机后,协调发动,有时被称为分布式拒绝服务攻击。

以上是攻击者可以发动的几种最重要的攻击类型。

防御措施 🛡️

接下来,我们看看可以采取哪些措施来保护、缓解或避免此类攻击。

我们可以通过使用身份验证来防止欺骗,强制用户在获得某些网络服务前证明自己的身份。密码可能是最简单的身份验证形式。智能手机中的SIM卡则提供了硬件身份标识和验证。

我们可以通过加密数据包内容来防止数据被嗅探。

我们可以通过使用数字签名来防止数据被篡改,这项技术允许数据接收方知晓数据是由特定的数字身份发送的,并且在传输途中未被篡改。

我们可以通过增加访问控制来防止对网络资源的未授权使用,具体方法是规定谁可以执行哪些操作,并要求用户在访问这些资源前再次证明自己的身份。例如,在马萨诸塞大学校园,你需要先向校园无线网络验证身份,然后才能使用它。

此外,还有被称为防火墙的专用硬件设备,它们被编程用于检测和缓解攻击。防火墙部署在边缘网络和核心网络中,可以被编程,例如,只允许特定用户或特定类型的流量进入或离开网络。我们将在学习第4章通用转发时,详细讨论防火墙和其他所谓的“中间盒”。

总结

以上是对“遭受攻击的网络”这一主题的一个非常高层次的概述。我们主要探讨了两个问题:一是攻击者在网络环境中可能实施的各类恶意行为;二是可以部署的用于保护、缓解和应对网络攻击的防御措施和技术类别。请记住,教材中有一整章专门讨论网络安全,并且在我们深入学习网络协议栈的过程中,我们将不断回到网络安全的主题上来。

1.7:计算机网络发展史 📜

在本节中,我们将回顾计算机网络的发展历史。我们的课程侧重于原理与实践,而通过这次历史概览,你将发现,其中一些原理和实践相对较新,但另一些则植根于60年前的研究,这甚至早于互联网诞生30年,也早于许多当代大学生的出生时间。

一些网络思想的历史更为久远。例如,电话网络已有超过一百年的历史,它必须处理交换和路由等问题。下图是1879年安装在巴黎中央电话局的第一台交换机。另一张更古老的图片展示了一个信号网络,这是一个中继节点,用于从源到目的地中继加密和解密的消息。这两件实物都陈列在巴黎的工艺博物馆中。如果你去巴黎,除了卢浮宫和奥赛博物馆,不妨也去工艺博物馆看看,特别是如果你对网络感兴趣的话。

现在,让我们回到计算机网络的历史。关于这段历史,网上有大量优秀的纪录片、网站和书籍资源。我们的讲述将把计算机网络的历史划分为五个时代。

分组交换的早期岁月 (1961-1972)

让我们从1961年开始。当时的电话网络是世界主导的通信网络。电话网络使用电路交换技术来传输信息,考虑到语音以恒定速率产生和传输,这或许是一个合适的选择。但随着计算机(包括分时计算机)的重要性日益增加,在20世纪60年代,人们很自然地开始思考如何将计算机连接起来,以便地理上分散的用户可以共享它们。这类计算机用户产生的流量很可能是突发性的,即活跃期与静默期交替出现。

第一份关于分组交换的论文由当时麻省理工学院的研究生、现任加州大学洛杉矶分校教授的伦纳德·克莱因罗克发表。他利用排队论证明了分组交换网络在处理突发流量方面的有效性。

到1964年,兰德研究所的保罗·巴兰开始研究分组交换在军事网络中的应用。与此同时,英国国家物理实验室的研究人员也在发展他们关于分组交换的想法。

令人惊叹的是,当时全球这三个研究小组在彼此不知情的情况下,都成为了分组交换技术的发明者。这或许就是时代的氛围。

1967年,美国高级研究计划局(ARPA)公布了一个名为ARPANET的网络计划,该网络后来成为世界上第一个分组交换计算机网络,也是我们今天所知的互联网最古老的直系祖先。1972年,第一个主机到主机协议——网络控制协议(NCP)完成,它是TCP/IP的直接前身。雷·汤姆林森编写了第一个电子邮件程序,此时ARPANET已发展到15个节点。

互联网络的兴起 (1972-1980)

最初的ARPANET只是一个独立的网络。在20世纪70年代早中期,其他几个独立的分组交换网络也开始出现。ALOHAnet是一个连接夏威夷群岛各大学的微波网络。DARPA(ARPA的后继机构)正在建设第二个分组交换网络,即分组卫星网络,以及分组无线电网络(这本质上是当今蜂窝数据网络的祖先)。Cyclades是法国的分组交换网络。

网络的数量在不断增长。事后看来,当时正是开发某种全面架构以连接不同网络的成熟时机。关于网络互联的第一项工作再次由DARPA承担。文顿·瑟夫和鲍勃·卡恩在1974年发表了一篇论文,阐述了他们称之为“网络互联”的原则,即如何构建一个网络的网络。

这些互联原则,我们将在本课程中深入理解,它们基本上定义了今天的互联网架构。以下是四个要点:

  • 极简与自治:能够轻松互联网络,而无需对网络内部进行更改。
  • 尽力而为服务模型:认识到数据包可能在网络内丢失或延迟。
  • 无状态路由
  • 整体去中心化的网络控制方法

1976年,鲍勃·梅特卡夫在其博士论文中发明了以太网。到70年代末,专有商业网络开始建设,ARPANET的节点数达到200个。

协议的爆发式增长 (1980-1990)

20世纪80年代的特点是ARPANET协议套件的标准化(我们今天仍在使用的许多协议)以及ARPANET社区内网络的持续爆炸式增长。构成当今互联网架构基础的许多最终部分都已到位。

TCP和IP在80年代初实现了标准化。SMTP电子邮件协议于1982年开发,至今仍是定义电子邮件的核心协议。域名系统(DNS)于1983年开发,用于将人类可读的互联网名称(例如 gaia.cs.umass.edu)映射到32位IP地址。SMTP和DNS都是应用层协议,我们将在下一章详细研究它们。

在80年代末,TCP进行了重要扩展,实现了基于主机的拥塞控制,即允许主机在发现因网络拥塞导致数据包丢失或延迟时降低发送速率。

80年代还出现了许多连接大学的新计算机网络。例如,BITNET为美国东北部的大学提供电子邮件和文件传输;CSNET(计算机科学网络)的成立是为了连接无法访问仍在运行的ARPANET的大学研究人员。1986年,美国国家科学基金会创建了NSFNET,以提供对NSF资助的超算中心的访问。到80年代末,NSF的角色扩大,成为连接区域网络并与其他网络互联的主要骨干网。

到80年代末,连接到这个“网络的网络”(已初具当今互联网的雏形)的主机数量达到了10万台。

商业化与万维网的诞生 (1990-2000)

现在进入90年代。90年代初发生的一系列事件标志着网络的持续演进和互联网即将到来的商业化。我们之前提到的互联网先驱ARPANET于1991年退役。NSFNET解除了对NSFNET用于商业目的的限制。我仍然记得收到第一封广告电子邮件的那天——在此之前,这些网络的可接受使用政策规定不得用于商业目的,禁止广告。你能想象吗?NSFNET于1995年退役,新的商业实体,即我们之前讨论过的像一级提供商那样的互联网服务提供商,如雨后春笋般涌现以承载骨干流量。

当然,从网络的角度看,90年代的主要事件是万维网的诞生。万维网由蒂姆·伯纳斯-李在欧洲核子研究中心发明。基于早在20世纪40年代超文本工作中的思想,伯纳斯-李和他的同事在90年代初开发了HTML(编写网页文档的标记语言)、HTTP(我们之前研究过的Web应用层协议)、Web服务器和浏览器——这四个Web的关键组件。

90年代末,Web的使用呈爆炸式增长,网络安全成为一个关键问题,互联网上的主机数量达到约5000万台。因此,在1989年到1999年的十年间,主机数量从10万增长到5000万,骨干网速度从每秒几兆比特提升到每秒千兆比特。

互联网新时代 (2005-至今)

那么,从2000-2005年至今,我们看到了什么?我们看到宽带接入在家庭中的大规模部署,速度达到每秒数十到数百兆比特。2008年,软件定义网络的概念被提出,我们将在第5章仔细研究它。

我们看到高速无线接入日益普及,首先是Wi-Fi,然后是日益普及的4G以及即将到来的5G网络。我们还看到服务提供商、内容提供商(如谷歌、Facebook和微软)创建自己的全球骨干网络,绕过商业互联网的一级ISP,以更接近最终用户。这样他们就能为社交媒体、搜索和视频内容提供近乎即时的访问。

此外,我们看到企业通过亚马逊网络服务和微软Azure在云中运行其服务。我们将在第5章研究数据中心网络等主题。

最后,我们看到智能手机的兴起和对移动性的日益重视。自2017年以来,实际上连接到互联网的移动设备数量已超过固定设备。

总结

在本节中,我们简要概述了计算机网络的历史。希望你已经看到了本课程将要研究的一些思想的出现。随着本节结束,我们也完成了对整个计算机网络的广泛概述。

在这次广泛的概述中,我们涵盖了大量的内容。我们首先提出了基本问题:什么是互联网?什么是协议?然后我们从网络边缘开始,讨论了设备、主机、服务器、接入网络。接着我们深入网络核心,探讨了分组交换和电路交换技术,并讨论了互联网作为“网络的网络”的结构。

之后,我们转向网络性能,讨论了数据包丢失、延迟和吞吐量问题。接着我们以更抽象的视角讨论了网络架构,包括分层架构、数据在协议栈上下流动时的封装概念。然后我们讨论了遭受攻击的网络。最后,我们以网络历史的快速概述结束了讨论。

希望你觉得这个广泛的介绍有趣且不至于过于 overwhelming。请记住,这里的目的是获得宏观视野、学习词汇、看清森林而非树木。我可以向你保证,在接下来的章节和课程中,我们将更详细地深入探讨这些主题,还有更多知识要学习,更多乐趣要体验。

2.1:应用层原理与实践 🚀

在本章中,我们将学习应用层的概念和实际实现。我们将从理解应用层在网络中的核心地位开始,探讨其与下层传输层的交互方式,并学习构建网络应用的基本模型和工具。


概述

应用层是网络存在的根本原因,它承载了我们日常使用的所有网络应用。我们将从熟悉的互联网应用入手,学习应用层协议(如HTTP)如何工作。本章将涵盖应用层的基本原理、两种主要的交互模型(客户端-服务器和对等网络),以及传输层为应用提供的服务。


应用层:网络存在的理由

在自顶向下的学习方法中,应用层是学习的起点。正如法语所说,它是“存在的理由”,是网络最初被创造出来的原因。网络的存在是为了支持各种应用。从我们熟悉的日常互联网应用开始学习,是一个很好的切入点。像HTTP这样的应用层协议非常易于人类阅读和理解,因此应用层是开始学习网络知识的绝佳场所。


本章目标

本章的目标是学习应用层的概念和实践实现。我们将首先了解应用层之下的传输层所提供的服务,因为应用层所做的任何事情都只能通过使用传输层的服务来完成。我们将探讨应用层各部分之间的两种交互形式:对等网络交互和存在时间更长的客户端-服务器模型。当然,我们还将通过研究流行的互联网应用层协议和基础设施来学习协议本身。

我们将详细研究在Web客户端和Web服务器之间运行的HTTP协议,快速浏览用于电子邮件的SMTP协议,花时间了解将域名(如 o.cs.um.edu)转换为32位IP地址(如 128.119.40.186)的域名系统,并探讨视频流系统和内容分发网络等分布式应用层基础设施。最后,我们将以套接字API作为本章的结尾。


无处不在的网络应用

作为互联网用户,我们都熟悉许多网络应用,从社交媒体、万维网、即时通讯、电子邮件、多人在线游戏,到流媒体音频/视频、Zoom等远程会议应用、互联网搜索和远程登录。有趣的是,所有这些应用(除了电子邮件和远程登录)都是在互联网架构(我们在1.7节学到的分层模型)和今天要学的传输层抽象被定义之后很久才开发出来的。这非常了不起。可以说,互联网的设计者做对了,因为他们发明的网络支持了他们当时甚至没有梦想过的应用。

我想在这里播放一段对互联网之父之一文特·瑟夫的采访片段。他指出,互联网架构师当时可能知道一些可能的互联网应用,但肯定不是我们今天看到的所有应用。他谈到了新应用的出现、我们在1.5节学到的分层概念、抽象的重要性以及获得一个稳定API的重要性,这些我们都将涉及。我想你会喜欢这段采访。

采访片段摘要:
文特·瑟夫回顾了互联网的发展。他指出,在互联网工作开始之前,电子邮件(由Ray Tomlinson发明,他使用了@符号)就已经存在。他们当时已经意识到这项技术的潜力,并用它来实现许多我们今天仍在使用的应用,如电子邮件、文件传输和远程访问分时计算机。

然而,互联网在1983年初投入运行,并在1989年商业化后,最重大的变化是蒂姆·伯纳斯-李开发的万维网。最初在1991年底发布时并未引起注意,直到NCSA的马克·安德森和埃里克·比纳开发了图形用户界面浏览器Mosaic,才让互联网看起来像一本带有格式化文本、图像、音频和视频的杂志,从而极大地影响了其可访问性和实用性。

互联网基础设施的设计被免费公开,没有专利限制,这极大地降低了访问计算机通信的门槛。随着公众接触到万维网,他们能够以极低的障碍向网络注入内容。内容的海量增长催生了搜索引擎(如Alta Vista、Yahoo,最终是Google和Bing)的需求。

另一个同样重要的里程碑是2007年智能手机的出现。移动电话使互联网更易访问,而互联网因其内容和功能使移动电话更有用。这两项技术相互促进,定义了互联网过去十年的发展。

所有这些背后的关键是分层架构。互联网是一个分层架构,TCP/IP是核心层,其上是实用协议(如文件传输),再之上是万维网(HTTP运行在TCP之上)。在移动电话之上,我们有了API,使得人们即使不了解底层移动电话技术也能轻松构建应用。正是这种必要的知识隔离和接口(无论是稳定的协议接口还是稳定的API)的稳定性,使得人们无需了解底层工作原理就能进行创新。


如何编写网络应用

现在,假设你想编写一个网络应用(实际上我们很快就要编写一些)。你需要做什么?我们已经看到互联网内部从源到目的地的一切是多么复杂。但事实证明,编写网络应用其实相当简单,因为我们可以抽象掉网络深处发生的所有复杂性。我们只需要关心两件事:第一,传输层提供了哪些服务;第二,应用层接口(API)对这些传输层服务是什么样子的。


网络应用的交互模型

当我们想要构建一个网络应用时,基本上有两种交互模型来描述网络应用的各个部分将如何相互交互:第一种是客户端-服务器模型,第二种是对等网络模型。由于客户端-服务器模型存在时间最长,也是第一种模型,让我们先来看看它。

客户端-服务器模型 👥

在客户端-服务器范式中,有一个服务器和一个客户端

  • 服务器:是一个始终在线的主机,通常拥有一个永久IP地址,以便客户端知道在哪里联系它。服务器可以托管在你的家中、公司、大学或商业数据中心。
  • 客户端:这是我们更熟悉的。客户端通过联系服务器并与之通信来操作。客户端通常间歇性地连接到互联网(例如,当你的手机或笔记本电脑连接到互联网时),因此它们没有永久的IP地址。最重要的是,客户端之间不直接通信,而是与服务器交互。

客户端-服务器协议的最佳例子是HTTP,其中客户端是Web浏览器,服务器是Web服务器。

对等网络模型 🔄

在对等网络架构中,没有中心服务器。相反,我们有的是对等体,这些系统将直接相互通信。它们向其他对等体请求服务,同时也向其他对等体提供服务。文件共享就是一个例子,一个对等体可以向其他对等体请求文件,同时也向这些对等体提供文件。这些对等体将间歇性地连接到互联网,并且会更改其IP地址。因此,随着对等体的加入和离开,管理这些对等体比在客户端-服务器环境中要复杂得多。


进程与通信

正如我们所看到的,网络应用将由一组相互交互的部分组成,无论它们是以客户端-服务器模型还是以对等网络模型交互。因此,它不是一个你编程、编译和运行的单一独立程序,而是多个程序,每个程序你都需要编写、编译和运行。

当这些程序运行时,它们被实例化为进程。你可以将进程视为程序的执行版本。如果这些进程在同一台计算机内相互通信,这通常被称为进程间通信。当它们运行在不同的计算机(即不同的主机和设备)上时,它们必须使用消息进行通信,而这正是我们在这里要关注的。

让我们看看两个分别在不同设备、不同主机上的进程如何相互通信。


客户端与服务器进程

我们已经讨论了很多关于客户端-服务器模型的内容,当我们开始讨论构建和编程客户端-服务器应用时,让我们在语言上更精确一些。我们将把发起通信(即首先联系另一方)的进程称为客户端,而被联系的进程称为服务器


套接字:网络通信的门户 🚪

通往传输层的应用程序编程接口使用一种称为套接字的抽象。进程将向它创建的套接字发送和接收消息。你可以把套接字想象成一扇门。我们创建这扇门,将消息发送进门,并从门接收消息。

发送和接收进程将依赖底层基础设施(传输层、网络层和链路层)将消息从发送进程的套接字传递到接收进程的套接字。需要注意的是,每当发送方和接收方通信时,都会涉及两个套接字,通信的每一侧各一个。


套接字寻址

现在,我们可以深入探讨实际使用套接字进行通信的一些机制。我们想讨论的第一个主题是寻址。可以这样想:当你想与某人通信时,你需要一些寻址信息。如果你给他们寄信,你需要知道他们居住的街道地址和城镇;如果他们住在公寓楼里,你需要公寓号;如果你打电话给某人,你需要电话号码,可能需要国家代码和区号;如果他们在公司,你还需要知道分机信息。使用套接字通信也是如此,我们需要一些关于如何寻址发送到套接字另一端(端点)的消息的信息。

当我们创建一个套接字时,将有两个重要的信息与之关联:

  1. 主机的IP地址
  2. 端口号

正如我们将看到的,一些端口号与特定的服务器和协议相关联。例如,连接到服务器的80端口将连接到该服务器的Web服务器;连接到25端口将连接到电子邮件服务器。我们将在本章中更详细地介绍端口。


应用层协议

早在第1.1节,我们就说过,协议定义了网络实体之间发送和接收的消息的格式顺序以及在消息接收和发送时采取的动作。因此,要定义一个应用层协议,我们需要定义:

  • 交换的消息类型
  • 它们的语法(即消息中的字段是什么)
  • 它们的语义(这些字段的含义是什么)
  • 在发送或接收消息前后采取的动作

协议有两种类型:

  • 开放协议:其消息语法、语义和动作都是公开可用的,并为所有人所知。例如,互联网协议在RFC中指定并公开可用。
  • 专有协议:通常由公司拥有,其操作不公开。例如,Zoom和Skype就是使用专有应用层协议的应用。

传输层服务

现在我们已经掌握了寻址和应用层协议的样子,让我们把注意力向下转移,看看传输层,特别是问自己一个问题:传输层可能向应用本身提供哪些类型的服务?

  1. 可靠数据传输:许多应用需要这项服务,例如文件传输或Web事务。我们需要能够可靠地将数据从一个进程传输到另一个进程。但并非所有应用都需要可靠的数据传输,例如分组音频(语音和视频)实际上可以容忍一些数据包丢失。
  2. 定时保证:电话和互动游戏确实需要低延迟才能有效,因此传输层可能提供从发送进程到接收进程的延迟保证。
  3. 吞吐量保证:某些应用需要一定的吞吐量才能有效。例如,流媒体视频需要一定的吞吐量才能发送视频所需的每秒比特数。其他应用,我们称之为弹性应用,能够利用它们能获得的任何吞吐量。
  4. 安全服务:例如,对传输的数据进行加密。

以下是一些常见互联网应用的传输服务需求:

  • 文件传输、电子邮件、Web文档不能容忍数据丢失,通常是弹性的(可以利用任何可用的吞吐量),并且不是实时敏感型应用。
  • 实时音频/视频、流媒体音频/视频、互动游戏:往往能容忍一些丢失,但对吞吐量和定时有更严格的要求

互联网的传输层服务

互联网的传输层只提供两种类型的服务:TCP服务UDP服务

TCP服务提供:

  • 发送和接收进程之间的可靠数据传输
  • 流量控制,防止发送方溢出接收方的可用缓冲区。
  • 拥塞控制
  • 面向连接,意味着在数据实际开始流动之前,客户端和服务器之间需要进行握手。
  • 不提供任何定时保证、吞吐量保证或安全服务。

UDP服务提供得甚至比TCP还少:

  • 不可靠的数据传输。即不作任何保证,UDP会尽最大努力将数据从发送方传递到接收方,但不承诺可靠性。
  • 不提供流量控制、拥塞控制、定时、吞吐量或安全保证。

你可能会问自己,为什么首先要有UDP?我们将会看到,一些应用层协议采用UDP的原因是,我们可以在应用层基于UDP构建这些UDP未提供的额外服务。

以下是流行的互联网应用层协议使用的底层传输服务。可以公平地说,TCP是迄今为止使用最广泛的传输服务,尽管UDP也有其用武之地。


应用层安全

让我们以快速的安全说明来结束对应用层原理和实践的讨论。20世纪80年代开发的初始套接字抽象没有与之相关的安全概念。发送到套接字的数据没有加密,也没有端点身份验证(向对方证明你就是你声称的人)的概念。如果你想这样做,实际上必须在应用层本身构建它。

我们稍后会看到,有一个广泛使用的安全层(实际上更像一个垫片层),称为传输层安全。它在TCP套接字之上的用户应用空间中实现,并提供加密、数据完整性和端点身份验证服务,可供应用程序使用。


总结

本节课中,我们一起学习了应用层的基本原理和实践。我们看到,一个应用实际上是一组分布式的、相互交互的、交换消息的进程。我们学习了用于构建应用的客户端-服务器对等网络范式。我们讨论了套接字,它是进程间通信的主要互联网抽象(我们还将学习更多关于套接字的知识)。我们谈到了寻址,然后一般性地讨论了传输层服务(传输层可能向应用提供哪些服务),最后以关于安全的简要讨论结束。

接下来,我们将开始研究具体的应用及其应用层协议。我们将从万维网和超文本传输协议开始。

2.2:Web与HTTP(第一部分)🌐

在本节课中,我们将要学习万维网(Web)和超文本传输协议(HTTP)的基础知识。我们将从Web和HTTP的快速概述开始,然后深入探讨两种HTTP连接类型:持久连接和非持久连接。接着,我们将研究HTTP使用的主要消息:请求消息和响应消息。最后,我们将通过了解一种在服务器端保持客户端连接之间状态的技术——Cookie,来结束本部分内容。这是关于HTTP两部分内容中的第一部分,内容非常丰富,让我们开始吧。

Web与HTTP概述

首先,让我们通过一个快速的回顾来开始关于Web和HTTP的讨论,为后续内容奠定基础。

一个网页由一个基础的HTML文件以及一组被引用的对象组成。这些对象中的每一个都可以存储在不同的Web服务器上。一个对象可以是一个HTML文件、一张JPEG图片、一个Java小程序、一个音频文件或许多其他东西。网页本身以及被引用的对象都可以通过一个称为URL(统一资源定位符)的地址来访问。URL包含一个主机名,以及在该主机上的路径名。

HTTP的客户端-服务器模型

现在,让我们开始学习HTTP。首先要知道的是,HTTP采用了我们在2.1节中刚刚学习过的客户端-服务器模型。

客户端可能是一个Web浏览器,如Firefox、Safari或Edge。它也可能嵌入在一个设备中,你甚至可能看不到它。服务器可能是一个只提供网页服务的传统Web服务器,也可能是一个更通用的服务器,如 gaia.cs.umass.edu,它提供多种服务。

在上面的动画中,我们看到顶部一台运行Firefox浏览器的PC向服务器发出HTTP请求并收到响应。底部我们看到一部运行Safari浏览器的iPhone也在发出HTTP请求并收到HTTP响应。这两个浏览器都在使用HTTP协议与Apache Web服务器通信。

HTTP与TCP

HTTP使用TCP协议提供的传输服务。一个HTTP事务的工作方式如下:HTTP客户端(例如你的Web浏览器)使用端口80打开一个到Web服务器的TCP连接(我们稍后会了解端口号)。然后,客户端和服务器之间交换一条或多条HTTP消息。最后,TCP连接被关闭。

HTTP是一种无状态协议。这意味着服务器不维护关于正在进行的请求的任何内部状态。一个对象对应一个请求和一个回复,仅此而已。没有诸如“这个事务有五个步骤,我们现在处于第三步,如果失败,我需要将状态回滚到这个五步事务开始之前”这样的担忧。HTTP没有这些,它是无状态的。你可能会问为什么?原因在于其简单性。正如我们将看到的,维护状态的协议需要处理多步事务失败时的清理问题,例如恢复到初始状态和解决不一致状态。

HTTP连接类型

HTTP连接有两种类型:持久连接非持久连接。重要的是要记住,浏览器和服务器之间的这些HTTP连接与传输层提供的TCP连接是不同的。

非持久HTTP中,打开一个TCP连接,然后最多发送一个对象,之后TCP连接就被关闭。下载多个对象需要建立多个TCP连接。我们将看到,首先需要一个往返时间(RTT)来打开TCP连接,然后另一个RTT来发送请求和接收响应。

持久HTTP中,同样会打开一个到服务器的TCP连接,但这次可以在客户端和服务器之间的单个TCP连接上串行传输多个对象。一旦请求并返回了这些多个对象,TCP连接就可以关闭。持久HTTP对应HTTP版本1.1,这可能是当今最常用的HTTP形式。

非持久HTTP操作示例

让我们看一个非持久HTTP操作的例子。

假设用户在步骤1A中输入一个URL www.someschool.edu,请求一个包含文本以及引用了10个JPEG图片的网页。在步骤1A中,我们看到客户端在 www.someschool.edu 的端口80上发起一个到HTTP服务器的TCP连接。在步骤1B中,主机上一直在端口80等待TCP连接的HTTP服务器接受这个TCP连接并通知客户端。注意,在步骤1A和1B中,实际上还没有任何HTTP请求流动。这发生在步骤2。在步骤2中,HTTP客户端通过刚刚建立的TCP连接发送HTTP请求消息。这条HTTP消息表明客户端想要接收那个基础的HTML文件。在步骤3中,服务器现在接收到这个HTTP请求消息,并构建包含所请求对象的响应消息,然后将此消息发送回HTTP客户端。发送响应消息后,在步骤4,HTTP服务器关闭TCP连接。在步骤5,HTTP客户端接收到包含HTML文件的响应消息,显示HTML文件,解析它,并找到那10个引用的JPEG对象。在步骤6,现在将不得不为每个引用的JPEG对象重复前面的五个步骤。

非持久HTTP的响应时间

现在我们可以看看非持久HTTP的响应时间。我们可以将响应时间定义为从用户首次在浏览器中输入URL到接收到并显示基础HTML文件所花费的时间。

让我们将RTT(往返时间)定义为一个非常小的数据包从客户端到服务器再返回所需的时间。

我们可以看到,非持久HTTP每个对象的响应时间包含以下部分:需要一个RTT来发起TCP连接,另一个RTT(第二个RTT)用于传输和接收HTTP请求以及返回HTTP响应的第一个字节,最后是服务器实际将文件传输到其互联网连接所需的时间。

因此,总的来说,非持久HTTP的响应时间是2个RTT加上传输文件所需的时间

持久HTTP的优势

我们已经看到,获取一个Web对象需要两个RTT。虽然多个对象通常可以并行获取,但两个RTT仍然是两个RTT。我们当然希望尽可能快地获取信息。通过一种简单的技术,实际上可以将这种延迟从两个RTT减少到一个RTT,那就是使用称为持久连接的技术。这也是现在大多数Web服务器的运行方式。

在持久HTTP(HTTP/1.1)中,服务器在发送响应后保持连接开放。随后,同一客户端和服务器之间的HTTP消息可以通过这个开放的连接发送,而无需等待建立新TCP连接所需的那个RTT。当客户端有新的请求时,一旦遇到被引用的对象,就会立即发送。

因此,我们可以看到持久HTTP如何将响应时间减半,变为一个RTT。

HTTP消息格式

既然我们已经了解了两种HTTP连接风格,现在可以深入探讨HTTP消息本身的细节了。回想一下1.1节,我们说协议定义了网络实体之间发送和接收的消息的格式和顺序,以及发送和接收这些消息时采取的操作。让我们来看看HTTP协议及其消息。

HTTP消息有两种类型:请求消息响应消息。让我们先看看请求消息。

HTTP请求消息

一个请求消息以单个请求行开始,该行以一个方法名开头,例如这里显示的 GET,后面是URL(在本例中是被请求的HTML文件的名称)、HTTP版本(本例中是1.1)和一个换行符(即回车换行)。单个请求行之后是许多头部行,它们提供附加信息。例如,请求所发往的主机名、发出请求的浏览器类型(本例中是Firefox)、可以接受的对象的类型和首选语言(本例中是美式英语),以及该连接应保持活动状态的事实。请求消息以一个空行结束。正如你所见,它非常易于人类阅读。

以下是HTTP请求消息的一般格式:我们看到请求行,后面跟着头部行。HTTP协议规范RFC 7320长达85页,包含了关于方法、头部字段名称和值的所有细节。幸运的是,对于我们网络专业的学生来说,我们不需要知道所有这些细节。但如果我们要实现一个HTTP客户端或服务器,就必须了解每一个细节。

当我们查看上一张幻灯片中的GET消息时,没有实体主体。某些请求消息(如我们稍后会看到的POST)需要实体主体,以便向服务器发送不在头部字段中的附加信息。

以下是四种类型的HTTP请求消息:

  • GET:我们已经见过GET方法。
  • POST:用于将已完成的表单数据上传到服务器。
  • PUT:可用于将一个新对象上传到具有给定URL的服务器,可能替换现有对象。
  • HEAD:请求一个与GET请求相同的响应,但没有响应主体。例如,这可用于确定将要检索的对象的大小,而无需实际检索该对象。

HTTP响应消息

现在让我们快速看一下HTTP响应消息。

响应消息以状态行开始。状态行的第一个信息是所使用的HTTP协议的版本号,在本例中是1.1。版本号之后是响应消息中最重要的两个信息:状态码简短消息。在本例中,显示的状态码是200,表示一切正常,状态短语是“OK”。

状态行之后是响应头部行,与请求消息类似,提供附加信息。例如,这里显示的有:发送响应的日期和时间、服务器类型(本例中是Apache服务器版本2.4.6)、Last-Modified字段显示文档最后修改的时间、Content-Length字段显示文档的长度、Content-Type字段指示返回的对象的类型(本例中是HTML文档)。最后是返回的对象的主体,在本例中就是HTML文档本身。

HTTP响应状态码

这里只是HTTP响应状态码和短语中的几个例子:

  • 200 OK:我们已经见过200 OK,表示请求成功。
  • 404 Not Found:当请求的文档在服务器上未找到时,你可能见过404 Not Found。

所有的响应状态码和短语都包含在RFC文档中。所以,如果你真的有兴趣了解所有的状态码和响应短语,可以查阅那里。

关于HTTP消息的讨论到此结束。正如所承诺的,它非常简单,只有两种类型的消息。同样如承诺的那样,它非常易于人类理解。我们可以查看那些HTTP消息并基本理解它们。

Cookie:在HTTP中保持状态

让我们通过回到无状态这个问题来结束对HTTP的初步研究。我们说过HTTP是一种无状态协议。事实证明,Web服务器实际上可以通过使用一种称为Cookie的技术来维护一些用户状态,记住用户过去做了什么,以及这可能如何影响用户在当前会话中想要做的事情。让我们来看看。

网站使用Cookie来维护关于用户(更具体地说是用户的浏览器)在事务之间的信息。使用Cookie有四个组成部分:

  1. 首先,服务器在某个时间点会向客户端发送一个Cookie。Cookie只是一个数字,包含在发送给客户端的HTTP响应消息的Cookie头部行中。
  2. 之后,当客户端下次向该服务器发出请求时,它会在Cookie头部行中附带该Cookie值发送给服务器。
  3. 服务器将记住它收到的所有请求以及它发送的与该Cookie值相关的响应。因此,它将拥有与该用户交互的历史记录。

让我们看一个例子。在这个例子中,左侧的客户端将向一个Amazon服务器(例如右侧的服务器)发出几个HTTP请求,该服务器有一个后端数据库来存储与Cookie相关的信息。客户端还拥有来自它访问过的其他网站的Cookie信息(例如来自eBay的Cookie),但它还没有来自Amazon的Cookie。

客户端像往常一样向Amazon Web服务器发出请求,最初没有Cookie行。当Amazon Web服务器收到HTTP请求时,它会创建一个Cookie,将Cookie和事务信息存储在其数据库中,并向客户端发送一个包含Cookie值的HTTP响应。

现在,在客户端的第二个请求中,客户端将其Cookie值包含给Amazon,允许Amazon服务器采取特定于Cookie的操作,或许会考虑到第一个HTTP请求。例如,也许第一个事务是请求查看一件商品,第二个HTTP请求想查看第二件商品。有了Cookie,第二个回复可以被精心设计,向客户端提供一个同时购买这两件商品的优惠,尽管第二个请求只想查看一件特定的商品。

客户端一周后再次访问,并再次提供Cookie。服务器可以再次采取特定于Cookie的操作。例如,它可以说:“嘿,过去一周我们很想念你。你确定不想买你上周看过的那些商品吗?”

在这个例子中,我们可以看到Cookie如何用于在HTTP交互之间在网站上存储关于用户的状态。

Cookie的用途与隐私

鉴于Cookie可用于在多个事务中存储用户状态,它们有很多用途:记住你之前已向网站验证过身份、记住你购物车的内容,或者根据过去的行为进行推荐。

你可能也读到过关于Cookie的许多隐私问题。Cookie可以让网站了解很多关于你的信息。存在所谓的第三方Cookie,它们可以被放入你的浏览器,并允许网站在多个网站之间建立共同的身份。你可能也听说过欧盟的《通用数据保护条例》(GDPR)。根据GDPR,对于网站运行并非严格必需的Cookie,只有在用户明确同意使用并收集个人数据后才能被激活。你可能最近注意到,在很多网站上,在你能够使用该网站之前,你必须同意特定的Cookie政策。

总结

本节课中我们一起学习了Web和HTTP的第一部分内容,我们已经学到了很多。经过快速介绍后,我们深入探讨了不同类型的HTTP连接,研究了请求和响应消息,并且还了解了Cookie——一种在服务器端记住用户与该服务器交互之间状态的方法。接下来在第二部分中,我们将更深入地探讨HTTP性能提升的一些其他方面,我们将研究Web缓存、条件GET请求,最后我们将研究HTTP版本2(最新的HTTP版本),并快速了解一下即将在未来一两年内到来的HTTP版本3。

2.3:电子邮件 📧

在本节中,我们将学习一个历史悠久的应用——电子邮件。电子邮件自1972年诞生以来,已成为我们文化的一部分。虽然它可能不是最令人兴奋的应用,但它是一个很好的客户端-服务器模型的例子,并且相对简单,非常适合我们进行学习。

我们将重点关注两个方面:首先,我们将探讨电子邮件应用的基础设施,包括用户代理(邮件客户端)、邮件服务器以及消息和消息队列。其次,我们将深入了解SMTP协议(简单邮件传输协议),它是电子邮件应用的核心。


电子邮件基础设施 🏗️

上一节我们介绍了HTTP的客户端-服务器模型,本节中我们来看看电子邮件如何采用类似的架构。作为一个分布式应用,电子邮件包含三个主要组件。

以下是电子邮件的三个核心组件:

  1. 用户代理:也称为邮件阅读器或邮件客户端。用户使用它来撰写、编辑和阅读邮件。
  2. 邮件服务器:相当于HTTP中的服务器。它为每个用户存储两类消息:收件箱(存放接收到的消息)和发送队列(存放等待发送到目标SMTP服务器的消息)。
  3. SMTP协议:用于将消息从用户代理或邮件服务器“推送”到另一个邮件服务器。它采用客户端-服务器模式,其中发送方(用户代理或发送邮件服务器)是客户端,接收方邮件服务器是服务器。

电子邮件发送流程示例 📤➡️📥

现在,让我们通过一个具体例子,看看当Alice想给Bob发送一封邮件时,涉及的各个步骤。

以下是Alice向Bob发送邮件的详细步骤:

  1. 撰写与发送:Alice使用她的邮件客户端(用户代理)撰写邮件,然后点击“发送”。
  2. 客户端到服务器:Alice的邮件客户端使用SMTP协议,以客户端身份联系Alice的邮件服务器,并将邮件“推送”到该服务器。
  3. 服务器间连接:Alice的邮件服务器现在需要将邮件发送给Bob的邮件服务器。为此,它首先与Bob的服务器建立一个TCP连接
  4. 服务器到服务器传输:Alice的SMTP服务器(此时作为客户端)通过已建立的TCP连接,将Alice的邮件发送给Bob的SMTP服务器。
  5. 投递与读取:Bob的服务器将邮件放入Bob的收件箱。之后,Bob可以随时启动他的用户代理,从服务器上读取这封邮件。


SMTP协议详解 🔧

SMTP协议由RFC 5321定义。它运行在TCP之上,使用端口25,确保邮件消息从客户端可靠地传输到服务器。

在TCP连接建立后,SMTP消息传输分为三个阶段。

以下是SMTP消息传输的三个阶段:

  1. 握手阶段:服务器发送220消息,客户端回复HELO,服务器再回复250消息(例如“Hello [客户端名],pleased to meet you”)。
  2. 消息传输阶段:客户端通过MAIL FROM:RCPT TO:DATA等命令指明发件人、收件人并传输消息内容。消息正文以单独一行的英文句点.结束。
  3. 连接关闭阶段:客户端发送QUIT,服务器回复221,随后关闭SMTP和TCP连接。

SMTP与HTTP的命令-响应交互类似,使用人类可读的ASCII文本和状态码。


SMTP与HTTP的比较 ⚖️

在深入邮件格式细节之前,让我们从高层次比较一下SMTP和HTTP协议。

以下是SMTP与HTTP的主要区别:

  • 推送 vs. 拉取:SMTP主要是推送协议,将消息从客户端推送到服务器。而HTTP是拉取协议,客户端从服务器拉取数据。
  • 消息内容:SMTP要求消息(包括头部和正文)必须编码为7位ASCII码格式。HTTP没有此限制。
  • 对象数量:单个SMTP消息中可以包含多个对象(如附件),而每个HTTP请求/响应通常只涉及一个对象。
  • 连接方式:SMTP使用持久连接,可以在一个TCP连接上传输多封邮件。

邮件消息格式 ✉️

那么,邮件消息本身是什么格式呢?其协议由RFC 2822定义,类似于HTML定义网页文档的语法。

一封电子邮件主要包含两部分:

  1. 头部:包含From:To:Subject:等行。请注意,这些头部信息与SMTP传输时使用的MAIL FROM:RCPT TO:命令是不同的。
  2. 正文:在头部之后,由一个空行分隔,接着是邮件正文。同样需要编码为7位ASCII格式。

邮件访问协议 📬

到目前为止,我们的讨论都集中在如何将邮件推送到目标SMTP服务器。那么,当邮件到达目标服务器后,用户如何取回并阅读它呢?

当然,这也有专门的协议。最广泛使用的电子邮件访问协议是IMAP(互联网消息访问协议),由RFC 3501定义。此外,用户也可以通过HTTP(例如Web邮箱)来访问邮件。


总结 📝

本节课中我们一起学习了计算机网络中最古老的应用之一——电子邮件。我们探讨了其基础设施,包括邮件服务器、邮件客户端和消息队列。我们还深入研究了SMTP协议,这是另一个客户端-服务器协议的例子,在某些方面与HTTP相似,但也有显著不同。

接下来,我们将学习DNS协议(域名系统)。我们将看到,它与SMTP和HTTP非常不同,不直接涉及终端用户,但却是互联网核心基础设施的关键部分。

2.4:域名系统(DNS)🌐

在本节中,我们将学习域名系统(DNS)。DNS是互联网中负责将主机名(如 gaia.cs.umass.edu)翻译成IP地址(如 128.119.40.186)的部分。我们将看到,DNS是一个令人惊叹的分布式应用,能够以巨大的规模和惊人的性能提供服务。

既然我们处于应用层,你可能会问,为什么我们要在应用层研究像名称翻译这样的核心互联网功能?答案是,DNS本身就是一个应用层协议和服务。它构建在TCP和UDP之上,并使用它们的服务,因此它确实是一个应用层服务。

本节内容很多。我们将首先讨论DNS的结构和功能,然后看看查询是如何被解析的,接着会研究DNS记录以及DNS协议的消息格式。让我们开始吧。

名称与标识符

顾名思义,域名系统(DNS)的核心是名称和标识符。就像一个人可以有多个标识符(如姓名、社保号、护照ID)一样,互联网主机也至少有两个标识符:一个主机名(如 gaia.cs.umass.edu)和一个IP地址(如 128.119.40.186)。DNS的角色就是提供名称与IP地址之间的翻译服务。

DNS:一个分布式数据库

域名系统(DNS)是一个分布式数据库。这个数据库的内容是包含主机名、服务和IP地址之间翻译信息的记录。DNS本身是一个分布在互联网上的服务器层次结构,这些服务器相互通信以提供名称翻译服务。

重要的是,DNS是作为应用层服务实现的。它由位于网络边缘的服务器实现,而不是网络内部的路由器和交换机。这反映了互联网的一个设计理念:保持网络核心简单,将复杂性放在网络边缘。随着我们深入学习传输层和网络层,会反复看到这个设计理念。

DNS的功能

DNS提供多种不同的功能。最广为人知的是IP地址到主机名的翻译服务,但它也提供其他一些重要服务:

  • 别名功能:将面向外部的名称(如 mail.cs.umass.edu)翻译成更复杂的内部主机名。
  • 服务解析:例如,返回与某个域名关联的邮件服务器的IP地址。
  • 负载均衡:可能有多个IP地址能够提供请求的服务(例如一个Web服务器),DNS会在这些可能的IP地址之间轮换,返回其中一个作为主要服务,从而实现一种负载均衡功能。

为何采用分布式设计?

考虑到DNS采用了分布式、去中心化的方法,你可能会问,为什么设计者不采用更中心化的方法?这里有几点考虑:

  • 单点故障:中心化方法代表一个单点故障。考虑到DNS是关键基础设施,这很危险。
  • 流量集中:考虑到DNS的负载,中心化方法会造成巨大的流量集中。
  • 性能延迟:考虑到性能的重要性(解析DNS查询时,毫秒都很关键),将其放在一个位置必然意味着地球上某些地方会有很长的往返时间(RTT)延迟。

总而言之,中心化方法无法应对每天数万亿次的查询规模。仅Akamai一家公司每天就处理超过一万亿次DNS请求。单一的集中式服务不具备分布式方法所能提供的计算能力、弹性或性能。

DNS概述

在深入DNS的技术细节之前,让我们先总结一下如何理解DNS。你可以将其视为一个高度分布式、大规模、高性能的分布式数据库。这是一个难题,但至少我们会看到其记录相对简单。

你需要从性能和规模的角度来思考它。它需要能够处理每天数万亿次(主要是读取)请求,并且必须以非常高的性能完成(毫秒都很关键)。在组织上,它也是高度去中心化的。有成千上万的组织负责管理这个分布式数据库中属于他们自己的那部分记录。这并非易事。

DNS的层次结构

我们说过DNS是一个分布式层次数据库。让我们从高层次看一下这个层次结构。

  • 根DNS服务器:位于树的根部。
  • 顶级域(TLD)服务器:下一层,负责所有 .com.edu.net 等域名的服务器。
  • 权威名称服务器:这些服务器对其域内的名称解析负有最终责任。例如,所有 umass.edunyu.edupbs.org 的名称。

如果一个客户端想要解析一个地址,比如 www.amazon.com,基本方法如下:

  1. 客户端首先联系根DNS服务器,获取负责所有 .com 域的TLD服务器名称。
  2. 客户端然后联系该TLD服务器,获取 amazon.com 的权威名称服务器名称。
  3. 最后,客户端联系 amazon.com 的权威名称服务器,获取 www.amazon.com 的IP地址。

根DNS服务器

既然我们喜欢自上而下地研究,让我们从DNS层次结构的顶部——根服务器开始。当其他服务器无法解析一个名称时,根服务器是求助的地方。你可以把它看作是最后的求助联系人。实际上,它并非真正提供翻译服务,而是启动翻译过程的地方。

这显然是互联网极其重要的功能,几乎是互联网的中枢神经系统。因此,安全性至关重要。根服务器及其相关的大部分基础设施由ICANN(互联网名称与数字地址分配机构)负责管理。

全球有13个逻辑根服务器,但每个逻辑根服务器本身实际上都被复制了。因此,对应这13个逻辑服务器的是全球近1000个物理服务器。仅在美国就有超过200个物理根服务器。

顶级域(TLD)服务器

从根域向下移动一级,我们找到顶级域(TLD)。顶级域中的每个服务器负责解析以 .com.edu.net.org 等结尾的地址。负责管理这些TLD域的协会被称为互联网注册管理机构。这些注册管理机构也是你想要注册新的 .com.edu.net 名称时需要去的地方。

权威名称服务器

权威名称服务器负责解析组织内部的名称。之所以说它是“权威的”,是因为正如俗话所说,“责任止于此”。这个DNS服务器对该组织的名称拥有权威,它说的就是最终答案。

本地DNS服务器

互联网上的每台主机都有一个关联的本地DNS服务器。当主机想要解析一个名称时,它会联系这个名称服务器。如果本地DNS名称服务器在本地缓存了该名称到地址的翻译对,它会立即响应请求主机。否则,它将启动解析过程。

如果你想知道你的本地DNS服务器的主机名,可以在你的计算机上输入以下命令之一:

  • 在macOS下,输入 scutil --dns
  • 在Windows下,输入 ipconfig /all

这些命令会显示你的本地DNS服务器的名称。

DNS名称解析示例

现在让我们看一个DNS名称解析的实际例子。假设请求主机位于 engineering.nyu.edu,它要请求解析名称 gaia.cs.umass.edu

以下是解析过程:

  1. engineering.nyu.edu 的主机首先向本地NYU DNS服务器(假设是 dns.nyu.edu)发送一个DNS查询消息。查询消息包含要翻译的主机名 gaia.cs.umass.edu
  2. 这个本地NYU DNS服务器的任务是解析这个名称。它首先向一个根DNS服务器转发查询消息。
  3. 根DNS服务器注意到 .edu 后缀,并向本地DNS服务器返回一个负责 .edu 的TLD服务器(顶级域服务器)的IP地址列表。
  4. 本地NYU DNS服务器然后向这些TLD服务器之一重新发送查询消息。
  5. TLD服务器注意到 umass.edu 后缀,并以马萨诸塞大学的权威DNS服务器 dns.umass.edu 的IP地址作为响应。
  6. 最后,NYU的本地DNS服务器再次向 dns.umass.edu 重新发送查询消息,而UMass的权威名称服务器则以 gaia.cs.umass.edu 的IP地址作为响应。

为了获取一个主机名的映射,总共发送了8条DNS消息(4条查询消息和4条回复消息)。我们很快会看到DNS缓存如何减少这种查询流量。

迭代查询与递归查询

我们在本例中看到的查询类型被称为迭代查询,因为NYU的本地DNS服务器是在迭代地查询一系列服务器,直到最终解析出 gaia.cs.umass.edu 的名称。

第二种查询解析形式被称为递归查询解析。在递归查询解析中,名称服务器不是用“我不知道,但你可以试试下一个”这类响应来回复请求(如迭代查询那样),而是自己承担起解析查询并返回最终答复的责任。

在递归查询的例子中,NYU的本地DNS服务器再次查询根服务器。然而,在这种递归情况下,根服务器查询TLD服务器,TLD服务器查询UMass权威名称服务器,然后依次回复给TLD服务器、根服务器、NYU的本地DNS服务器,最后回复给查询主机。

由于这种递归查询形式将负担放在了层次结构上层的服务器上,它在实践中并不常用。相反,本地DNS服务器采用的是迭代查询。

DNS缓存

我们已经看到,获取一个名称到地址翻译的DNS记录可能涉及大量工作。因此,如果能以某种方式利用这项工作(即缓存该记录一段时间)就太好了,以防另一个相同的记录请求到来。

一旦一个DNS服务器学习到一个映射,它会将该映射缓存一段时间。如果未来有对该映射的请求,它可以立即返回缓存的回复来响应查询。因此,我们看到缓存提高了响应时间,并减轻了DNS基础设施的负载,一举两得。

缓存条目最终会超时,并在一定时间(生存时间,TTL)后从缓存中消失。然而,需要注意的是,如果DNS记录发生更改,缓存的条目可能会过时。不过,DNS并不担心陈旧和过时的缓存条目,它们最终会超时,即使在此期间有一些不准确的信息在流传。

例如,如果一个命名主机更改了其IP地址,在所有TTL过期之前,这个更改不会在互联网范围内被知晓。然而,在这种尽力而为的名称到地址翻译方法中,获得的好处是:不需要昂贵且复杂的机制来定位和清除缓存中的过时信息。

DNS资源记录

关于DNS的结构和功能我们就讲到这里,但我们还有两件事要看:DNS内部的资源记录,以及DNS协议消息的格式。

DNS数据库记录是一个四元组,包含名称、值、类型和TTL(生存时间)字段。DNS记录有多种不同类型,以下是四种常见的类型:

  • 类型 A(地址记录):记录包含一个主机名及其IP地址。此记录用于名称到地址的翻译。
  • 类型 NS(名称服务器记录):名称是一个域名(如 umass.edu),值是该域的权威名称服务器的主机名。
  • 类型 CNAME(规范名称记录):用于名称别名。
  • 类型 MX(邮件交换记录):用于提供与域关联的邮件服务器的名称。

DNS协议消息格式

接下来,让我们看看DNS协议消息的格式。查询和回复消息具有相同的格式,如右图所示。请记住,DNS是一个查询-响应协议。

这里的ID字段是一个16位的数字,由查询者选择。当发送响应回复查询时,该响应采用与查询相同的ID值,以表明这是对该特定查询的响应。

标志字段用于指示这是查询消息还是回复消息,是否请求了递归(如果是查询),以及回复是否权威(如果是回复消息)。接下来的四个字段用于指示协议消息其余部分中的问题和回答的数量。

在查询的情况下,一个问题(例如,将主机名解析为IP地址)的主机名会放在这个字段中。在对这种查询的回复情况下,一个类型为A的资源记录(包含主机的名称和IP地址)会被插入到这个字段中。RFC 1035定义了所有这些字段以及资源记录。

实践:创建公司网络

为了帮助我们整合所学到的关于DNS的一些知识,假设你现在创建了一家公司,名叫“Network Utopia”。它有一个网络,并且你希望它在互联网上有存在感,你希望公司服务能被互联网上的其他人通过你的站点 networkutopia.com 访问到。你需要做什么?

显然,DNS将会参与其中,因为为了让用户访问你的网络,他们需要知道你网络中服务器的IP地址。即使 networkutopia.com 这个名字变得非常有名,也没人会知道你服务器的IP地址。因此,你当然需要为此使用DNS。

首先,你需要在像Network Solutions这样的DNS注册商(我们之前提到的注册公司)那里注册你的名称 networkutopia.com。你还需要一组IP地址(我们将在第4章讨论如何获取)。现在假设你已经为你的服务器获得了一系列IP地址。

然后,你需要将你的权威名称服务器的名称和地址提供给注册商。注册商会将你的名称服务器名称插入一个NS记录,并将其IP地址插入一个A记录,放入全球DNS数据库中。这就是需要在注册商那里做的全部事情。

你网络中所有其他服务器的地址将由你的权威名称服务器提供给那些知道这些服务主机名的查询者。最后,你需要启动你的权威名称服务器,并用你网络中服务器的资源记录来填充它。

DNS安全

让我们以关于DNS安全的简短说明来结束。既然你了解了DNS的作用,你就能看到它对互联网的运行是多么绝对关键。如果DNS停止工作,除非你知道主机的IP地址(这几乎不可能),否则将无法联系任何主机。因此,保护DNS至关重要。

DNS主要通过防火墙来防范拒绝服务攻击。DNS还需要确保进入数据库的记录来自授权来源,因此身份验证服务将在保护DNS方面发挥关键作用。我们将在第7章学习身份验证服务。

总结

本节课我们一起学习了DNS——一个绝对关键的网络功能,它必须以惊人的规模和性能工作。我们探讨了几个方面:讨论了DNS的功能和结构,了解了名称是如何被实际解析的,并研究了DNS数据库内部的资源记录以及DNS协议消息的格式。

接下来,我们将学习另一个高度去中心化、高性能的分布式应用:视频流。

2.5:BitTorrent 与 P2P 网络应用 🧩

在本节课中,我们将学习对等网络应用的基本原理,并以 BitTorrent 为例,探讨其工作机制。我们将从传统客户端-服务器模型与 P2P 模型的对比开始,逐步深入到 BitTorrent 的具体运作细节。

概述:P2P 应用与 BitTorrent

对等网络应用的核心特征是不依赖一个持续在线的服务器来监听连接。在这种模型中,任意终端系统可以直接相互通信。对等节点向其他节点请求服务,同时也为其他节点提供服务。P2P 网络的可持续性关键在于,提供的服务规模至少要与请求的服务规模同步增长

P2P 网络的运行面临两大主要挑战:

  1. 节点可能随时加入或离开网络,因此特定节点提供的服务会时有时无。
  2. 随着时间的推移,节点的 IP 地址很可能会发生变化。

目前最常见的 P2P 应用是 BitTorrent,我们将在后续幻灯片中以其为例进行讲解。首先,让我们通过一些计算来看看 P2P 文件传输的潜在优势。

传统客户端-服务器模型 📊

在传统模型中,文件源自服务器,需要分发给多个客户端。这里的限制因素是服务器上传文件和客户端下载文件可用的带宽。

为了让所有客户端都直接从服务器接收文件,服务器必须上传 n 份文件副本。我们可以通过以下公式计算完成此任务所需的时间:

分发时间 ≥ max( n * F / us, F / dmin )

其中:

  • n 是客户端数量。
  • F 是文件大小。
  • us 是服务器的上传带宽。
  • dmin 是最慢客户端的下载带宽。

这个公式假设所有客户端同时发起请求。从可扩展性来看,下载时间会随着客户端数量 n 线性增加。

对等网络模型 📈

现在让我们看看 P2P 场景。文件仍然从服务器上的一个位置开始。服务器至少需要上传一份完整的文件副本。每个客户端最终也需要获得自己的文件副本。因此,总体来看,所有客户端总共需要 n * F 比特的数据。

但在 P2P 模型中,所有客户端的上传带宽也将有助于提高文件分发速率。整个文件分发过程的速度不可能快于服务器上传一份副本的速度,也不可能快于最慢客户端下载一份副本的速度。然而,在典型情况下,分子(总数据量)随 n 线性增长,但分母(总上传带宽)也随着更多节点加入网络而增加,因为它们会为向其他节点上传文件做出贡献。

模型对比 📉

让我们在图表上比较这两种模型。我们看到服务器向终端节点分发文件所需的时间呈线性增长。同时我们也看到,随着更多节点加入 P2P 网络,将文件传输给每个新增节点所增加的时间在减少,边际增量越来越低。这种性能表现远优于线性增长的分发时间。

上一节我们对比了两种模型的性能差异,本节中我们来看看 P2P 原理在实际中是如何运作的。让我们以 BitTorrent 为例。

BitTorrent 工作机制 ⚙️

作为 BitTorrent 协议的一部分,每个文件被分割成 256 KB 的块。这允许节点更快地开始共享文件的片段,而不必等待整个文件传输操作完成。一旦第一个块被上传给一个节点,该节点就可以在下载另一个块的同时开始共享它。

以下是 BitTorrent 中的几个关键术语:

  • 种子:指正在交换特定文件的一组对等节点。一个给定的节点可以同时参与许多不同的种子。
  • 追踪器:是一个服务器,用于维护参与特定种子的节点列表。

从以上解释可以看出,BitTorrent 并非纯粹的 P2P 协议,因为它仍然依赖一个持续在线的服务器,即追踪器。如果追踪器失效,协议将无法工作。尽管如此,BitTorrent 已有增强功能,允许其使用分布式追踪器,而非集中在一台服务器上的追踪器。

加入与数据交换流程 🔄

让我们梳理一下新节点想要加入一个种子时发生的过程。假设 Alice 想加入一个已经活跃的种子。

首先,她必须联系追踪器,以获取参与此种子的节点列表。这意味着追踪器必须位于一个可预测的位置,否则 Alice 将无法找到它。

一旦她获得了节点列表,Alice 就可以开始交换数据块。起初,Alice 没有任何数据块可以贡献,因此她需要一种方式从其他节点获取一些块。当她拥有一个或多个块后,她就可以开始上传这些块,同时继续下载更多块。

节点加入和离开种子的过程被称为 节点流失。网络中发生的流失越多,及时将所有数据块交付给所有节点就越具挑战性。

当一个节点拥有整个文件后,它可能会离开种子。如果它上传的块数尚未至少与其下载的块数一样多,这通常被认为是自私的行为。在下载完所有块后仍留在种子中被称为 做种,即为其他节点提供一个额外的、完整的文件副本以供获取块。

块选择与激励机制 🎯

随着进程推进,不同的节点将拥有文件的不同数据块。重要的是,在任何给定时间,所有数据块仍然存在于种子中。

每个节点会定期向其连接的邻居询问它们拥有的块列表。Alice 会从她的节点那里请求她尚未拥有的块,优先请求最稀缺的块。例如,如果在她所有的节点中,某个特定块只有一个副本,Alice 会首先请求它。一旦她获得了一个副本,那么在同一组节点中,该块就至少有两个副本了。这有助于保护种子,防止出现特定块的唯一副本位于一个决定离开种子的节点上,从而导致其他节点都无法完成下载的情况。

节点对于向哪些节点发送文件块是有选择性的,它们会优先考虑当前发送速率最高的节点。节点会定期重新评估哪些邻居速度最快。这激励了节点如果想要快速下载块,就必须快速上传。

该过程还有另一个组成部分,称为 乐观解除阻塞。Alice 会随机选择一个节点,并向其发送一个它正在请求的块。这是引导过程,使得那些没有任何块的节点可以开始下载种子。

示例:以牙还牙策略 🤝

让我们看一个“以牙还牙”策略的例子。Bob 正在请求块,但他没有任何块可以上传,或者可能只是没有 Alice 需要的块。无论哪种情况,Alice 随机选择了 Bob 并乐观地解除了对他的阻塞,这意味着她开始发送给他一个他仍然需要的块。

此时,Bob 重新计算他的前四个提供者,而 Alice 是其中之一,因此 Bob 通过发送给 Alice 一个块作为回报。事实证明,Alice 和 Bob 连接良好,因此 Bob 现在也成为了 Alice 的前四个提供者之一,他们都通过更快地获取文件块而受益。这通过让连接良好的节点彼此交换更多块,提高了整个 P2P 网络的效率。

总结 📝

本节课中,我们一起学习了对等网络应用的基本原理。我们首先比较了传统的客户端-服务器模型与 P2P 模型在文件分发效率上的差异,了解到 P2P 模型在可扩展性方面更具优势。接着,我们深入探讨了 BitTorrent 这一典型 P2P 应用的工作机制,包括其文件分块、追踪器角色、节点加入与流失、稀缺块优先选择以及“以牙还牙”与“乐观解除阻塞”等核心激励机制。这些机制共同保障了 BitTorrent 网络的高效与健壮运行。

2.6:视频流与内容分发网络 📺

在本节中,我们将暂时将焦点从应用层协议上移开,转而关注用于实现服务的应用层分布式基础设施。我们将要研究的服务是视频流。这是一个我们熟知、喜爱并可能频繁使用的应用。为了实现视频流服务,存在一些非常复杂的分布式基础设施的绝佳案例,因此有很多值得学习的内容。我们将从视频作为一种应用开始,然后,正如我们所知,互联网可能在发送方和接收方之间引入可变的延迟。因此,我们将探讨客户端技术——缓冲自适应播放——以减轻可变互联网延迟的影响。接着,我们将研究一种名为 DASH(基于HTTP的动态自适应流)的技术,并了解DASH如何适应源与目的地之间可用容量(带宽)的变化。我们将通过一个例子来了解DASH,并探讨内容分发网络以及Netflix作为应用实例。这里有很多内容需要了解和学习,让我们开始吧。

视频流概述 📊

视频流流量是互联网带宽的主要消耗者。据估计,80% 的住宅ISP流量是视频流流量。当我们思考视频流时,几个挑战显而易见。一如既往,存在规模问题。我们希望能够触达数千万甚至数亿用户。第二个挑战是异构性。有些用户是移动的,有些是固定的;有些拥有高速宽带连接,而另一些则处于带宽匮乏的连接中。我们将如何应对这种异构性?正如我们将看到的,答案在于一个非常复杂的应用层分布式基础设施。

视频的结构与编码 🎞️

让我们从观察视频本身的结构来开始讨论视频流。视频只是一系列编码图像(有时称为)的序列,通常以每秒24或30帧的速度捕获。每幅图像都是一个像素矩阵。这些像素通常经过编码,以利用图像冗余来减小图像大小,从而减小视频大小。

存在空间编码,它利用单幅图像内的冗余。例如,在这幅图像中,与其存储n个重复的紫色天空像素值,不如存储单个像素值“紫色”以及重复次数。这样只需两个值来编码图像的该部分,而不是n个值。这是帧内编码

我们还可以进行帧间编码。如果图像在帧之间变化不大或仅略有变化,那么我们可以只发送帧之间的变化,而不是发送整个新帧。

视频编码方法主要有两大类:恒定比特率视频可变比特率视频。顾名思义,在恒定比特率视频中,视频随时间变化的编码速率是固定的、恒定的。而在可变比特率编码中,编码速率会随时间变化,因为空间和时间相关性随时间而变化。

这里我们看到一些编码标准,其编码速率范围从MPEG-1的1.5 Mbps到MPEG-4(例如,我们录制这些视频所用的格式),其速率可达10 Mbps甚至更高。

视频流的技术挑战 ⚙️

现在,当我们思考与流式传输存储视频相关的技术挑战时,这里存在两个复杂性来源。

第一个与客户端和服务器之间可用带宽量会随时间变化这一事实有关。家庭网络、接入网络、核心网络、视频服务器集群内的网络或视频服务器系统本身内部都可能发生拥塞。因此,可用带宽量会随时间变化,我们需要能够适应这种变化。

其次,我们已经看到,互联网中源与目的地之间(客户端与服务器之间)的延迟也会随时间变化。它不像电路那样,从源到目的地有固定的延迟和保证的带宽。在分组交换网络中,我们会遇到可变的延迟,因此我们也需要在客户端适应这种情况。

流式传输存储视频的三个步骤 🔄

让我们从宏观角度开始,看看流式传输存储视频涉及的三个步骤。首先,视频被录制。其次,视频由服务器发送。最后,第三,视频在客户端播放。我们将在此图的背景下进行说明。在X轴上,时间向前推进。在Y轴上,我们有已录制、已发送或已播放的累积数据量,正如我们将看到的。

在这第一条黑色阶梯曲线中,我们展示了视频被录制的过程。为简单起见,我们假设它是恒定比特率视频。我们看到随着时间的推移,越来越多的视频被录制,累积数据量以恒定速率上升,例如,每次跳跃代表一个新帧的录制数据。

然后,该视频被存储,并最终由服务器在此处传输。在这个例子中,视频以与录制时相同的速率传输。它是一个以5 Mbps录制的MPEG视频,然后以5 Mbps发送。但它可以发送得更快甚至更慢。为简单起见,我们假设它只是以录制速率发送出去。

经过此处显示的一些网络延迟后,视频播放开始在接收端进行,同样以与录制时相同的速率。现在我们明白为什么这被称为流式视频了。如果我们看这里的时间点,我们可以看到客户端正在播放第2帧,而服务器正在发送第10帧。

客户端不是在播放前下载整个视频,而是在服务器仍在发送时就开始播放。也就是说,流式传输视频中较晚的帧。您可能想思考一下流式视频相对于先下载整个视频再播放的优势。通过流式传输,客户端可以更早开始播放。如果客户端没有观看整个视频,我们也不会浪费大量带宽传输未被观看的视频部分。

客户端播放约束与缓冲 🛡️

现在,在客户端,我们必须处理一个称为连续播放约束的限制。这意味着客户端播放的时序必须与视频最初录制时的时序相匹配。所以,您坐在客户端,正在播放视频。每个人都参与其中。是时候播放一段视频了。那段视频最好已经从服务器到达客户端以便播放。如果没有,我们就会看到那个旋转的图标,我们都在某个时候见过。

这里的挑战来源是视频服务器和客户端之间的可变延迟。为了减轻这种延迟,我们将使用缓冲来吸收部分延迟变化。

还存在其他挑战,例如如何处理客户端操作,如快进和倒带。如果数据包丢失,并且我们通过TCP进行流式传输,它们将被重传,从而导致额外的延迟。因此,我们需要解决的一个基本挑战是可变网络延迟。让我们看看这是如何完成的。

应对可变网络延迟 📉

让我们再次回到这个图,并再次假设服务器以恒定速率传输恒定比特率视频,如我们之前看到的红色阶梯曲线所示。此图与前一图的区别在于,现在每个视频帧的网络延迟将是可变的。请记住,在前一图中,网络延迟是固定的,黑色阶梯曲线有整齐、均匀的阶梯步长,因为网络延迟被假设为恒定。在这里,步长不再整齐均匀。有时会有更长的水平步长,例如这里和这里,当一帧的网络延迟明显长于前一帧时。有时水平延迟很短,例如这里和这里,当一帧的网络延迟明显短于前一帧时。

由于网络延迟可变,帧不再以匹配播放所需时序的时序被接收。为了适应这种所谓的网络延迟抖动,客户端将使用缓冲区来平滑延迟,如此处的蓝色播放曲线所示。客户端现在也会在开始播放前等待。然而,一旦播放开始,客户端将以此处蓝色所示的时序播放视频,该时序与原始时序(此处红色所示,以及我们之前图中黑色所示)相匹配。

客户端应该等待多长时间?嗯,这是一个价值百万美元的关键问题。如果初始客户端播放延迟太短,且帧延迟变化很大,一帧可能无法及时到达以供播放。这被称为饥饿,并导致我们习惯看到的旋转图标,即视频冻结。如果初始客户端播放延迟太长,那么用户在视频开始播放前必须等待更长时间,而用户讨厌等待。

动态自适应流:DASH 🚀

了解了客户端缓冲和播放后,现在让我们将注意力转向客户端和服务器之间可用带宽量变化的挑战。缓冲对于吸收可变延迟非常有效,但是,当客户端和服务器之间存在的可用带宽量不足以支持视频从服务器传输到客户端的速率时,会发生什么?在这种情况下,我们需要另一种解决方案,这就是DASH(基于HTTP的动态自适应流)发挥作用的地方。

以下是DASH的工作原理。让我们从服务器端开始。将要流式传输的视频被分成。每个块然后以不同的编码速率、不同的质量级别进行编码,并存储在单独的文件中。较高质量编码的视频块将关联到较大的文件,因此需要更长的时间、更高的带宽才能下载。

这些代表不同编码的不同块将被存储在内容分发网络内的不同节点上。最后,会有一个清单文件。清单文件将告诉客户端以特定编码级别获取此块,并指明可以前往的服务器节点(CDN节点)。

在客户端,客户端将执行以下操作。它将定期估计可用的服务器到客户端带宽量,并自问:这条路径能否支持更多流量?我能否以更高的保真度请求下一个块?当客户端需要一个块时,它将查阅清单并一次请求一个视频块,选择根据当前可用带宽估计可持续的最大编码速率。它可以在不同时间点选择不同的编码速率,取决于当时的可用带宽量,并且可以选择从哪个服务器请求块。

因此,我们看到在DASH中,智能和控制实际上在客户端一侧。客户端获得信息(列出其选项的清单文件)。然后客户端监控性能,以确定编码速率和它将从中发出下一个请求的CDN节点。这在客户端放置了大量智能。

内容分发网络 🌐

那么,让我们退一步,问自己一个基本问题。我们希望如何构建一个能够向潜在数千或数十万同时在线客户端流式传输视频的应用,并且视频可以从一个可能包含数百万视频的目录中选择?有哪些选项可以做到这一点?

我们可能首先想到一个巨型服务器。一个拥有所有视频的庞大服务器,它将处理来自所有客户端的所有请求。那么,这样做的问题是什么?嗯,希望这对您来说是显而易见的。它是一个单点故障。显然,网络中和视频服务器本身都存在潜在的拥塞可能。最后,视频服务器位置与地球上某些点之间将存在长延迟。简而言之,这种解决方案根本无法扩展。

第二种选择,实践中采用的方法是构建一个大型分布式基础设施,在不同地理分布的站点存储和提供视频块的副本。这是应用层内容分发网络的一个例子。该网络中的服务器加载了要提供的内容,清单文件或CDN DNS服务器将把客户端指向其请求的内容。

在实践中,互联网CDN有两种方法。在深入方法中,CDN服务器被深入推入互联网边缘的许多接入网络。2015年,一家总部位于剑桥的CDN公司Akamai部署了超过25万台CDN服务器,分布在120多个国家。我补充一点,在2018年,我们Umass的一位教员Ramesh Sitaraman因构建Akamai的内容分发网络而成为获得ACM SIGCOMM网络系统奖的团队成员之一。

第二种方法被称为带回家方法。在这种方法中,数量较少但规模较大的服务器集群位于存在点,这是我们在学习第1.5节时了解到的。

CDN流式传输示例:Netflix 🎬

现在,让我们通过一个例子来了解通过CDN流式传输视频的过程。这是一个网络设置。我们看到这里的Netflix中心,以及内容副本(例如,包括《Maddin》的副本)分布在其CDN节点周围。这是我在家,我想观看《Maddin》的某一集。

因此,我的Netflix客户端应用程序向Netflix中心发送请求,说:“嘿,Jim想看这一集。”Netflix中心然后返回一个清单文件,列出视频块及其位置,正如我们之前看到的。我的Netflix客户端应用程序可能随后开始从这个附近的CDN服务器检索视频,执行缓冲和客户端播放,正如我们之前看到的。如果那条路径恰好变得拥塞,我的Netflix客户端可能会选择从这里的这个服务器获取下一个块。

现在,如果您思考Netflix,它不是一个ISP。它是关于内容的,而不是关于网络的,但它利用ISP提供的网络,在应用层通过ISP的网络交付内容。因此,像Netflix这样的服务有时被称为OTT服务,因为它是一个构建在互联网基础设施之上的应用层服务。您可能还记得在我们第一堂课上,当我们问自己“什么是互联网”时,我们以两种方式回答了这个问题:我们给出了一个“螺母和螺栓”的答案,描述了互联网的各个部分;但我们也通过说互联网是一个服务基础设施,在其上构建了惊人的应用来回答这个问题。这正是这里看待OTT服务的观点。

总结 📝

我希望您觉得本节内容有趣。我们在这里稍微偏离了重点,也许从关注协议转向关注应用结构本身,特别是用于流式传输存储视频的大规模分布式应用层基础设施的案例。我们首先研究了流式视频的特性,然后探讨了客户端的缓冲技术和播放策略,接着我们研究了分块技术,并在那里遇到了基于HTTP的动态自适应流DASH,最后我们快速浏览了内容分发网络,以及通过内容分发网络流式传输存储视频的例子。

2.7:套接字编程 🖥️

在本节中,我们将学习套接字编程。套接字是应用层代码与其下层传输层服务之间唯一的应用程序接口。我们将学习套接字抽象的概念,并学习如何编程UDP套接字和TCP套接字。我们将通过一个使用Python和套接字编写的简单客户端-服务器应用程序示例来逐步讲解。

概述:什么是套接字?

在本节中,我们将学习如何构建在互联网上进行通信的客户端-服务器应用程序。这意味着它们需要使用套接字进行通信。套接字是位于应用层和传输层之间唯一的API。如果你想直接访问互联网的传输层服务,将应用层消息从分布式应用的一部分发送到另一部分,你就必须使用套接字。这对所有操作系统都是如此。

从操作系统的角度来看,你的应用程序运行在用户空间,而传输层及其以下的互联网协议栈各层则位于操作系统内部。套接字就是你的应用层程序与下层操作系统内的传输层之间的接口或“门”。

互联网套接字API只提供两种类型的传输层服务。第一种由TCP提供,它提供从一个进程到另一个进程的、可靠的、拥塞控制的、流量控制的、面向字节流的数据传输。第二种是UDP服务,它提供从一个进程到另一个进程的、面向数据报的、不可靠的服务。

接下来,我们将用Python编写一个非常简单的客户端-服务器应用程序,近距离地观察套接字编程。我们将首先使用UDP套接字,然后使用TCP套接字。在这个应用程序中,客户端将从键盘读取一行字符数据,并将该数据发送到服务器。服务器接收数据,将字符转换为大写,然后将转换后的大写文本发送回客户端。客户端接收来自服务器的数据,并将其显示在屏幕上。这是一个简单的示例,但它将展示如何在实践中使用套接字。

UDP套接字编程 📨

使用UDP服务时,客户端和服务器之间没有连接。这意味着在客户端和服务器可以通信之前,不需要进行握手。这也意味着当客户端要向服务器发送数据时,必须明确地附上服务器的IP地址和端口号。在服务器端,当服务器收到数据报时,必须提取出客户端的IP地址和端口号,以知道它在与谁通信。使用UDP,数据在客户端和服务器之间传输时可能会丢失或顺序错乱。因此,从应用程序的角度来看,UDP服务是关于从客户端到服务器的不可靠且实际上是无序的数据报传输。

现在,让我们看看在我们之前讨论的那个简单应用程序中,客户端和服务器创建、使用和关闭套接字所采取的步骤序列。我们将从UDP套接字开始,因为从编程意义上讲,它们是最简单的。

创建套接字

客户端和服务器首先需要创建要使用的套接字。以下是客户端创建名为clientSocket的UDP套接字对象的Python代码片段:

clientSocket = socket(AF_INET, SOCK_DGRAM)

让我们看看这些参数。第一个参数AF_INET表示这将是一个互联网类型的套接字。第二个参数sock_DGRAM表示这是一个UDP数据报套接字,而不是TCP套接字。请注意,我们在创建客户端套接字时没有指定其端口号。我们将让操作系统为我们分配。不过,如果我们愿意,可以使用bind方法请求一个特定的端口号。

在服务器端,我们做同样的事情,创建一个名为serverSocket的套接字。

发送和接收数据

在客户端,我们将创建一个应用层消息(一个字符串)。当我们将此消息发送到套接字时,还需要明确地将服务器的IP地址和端口号附加到消息上,然后将该信息传递给客户端套接字。

你可能会问,我们如何知道服务器的IP地址和端口号?在某种程度上,你必须知道。互联网没有一个让服务器注册服务、客户端可以查找该服务的目录服务。有些网络架构包含这样的服务,但互联网上,你只需要知道主机名或IP地址以及端口号。如果你只知道主机名,则需要通过调用本地DNS服务器将其转换为IP地址。

关于端口号,需要记住一点:有些端口号是标准化的,即所谓的“知名端口号”。例如,HTTP的端口80、SMTP的端口25、DNS服务器的端口53。

回到我们的例子,客户端发送的数据报最终被服务器接收,应用层消息从serverSocket中读取出来。服务器也能获知发送客户端的IP地址和端口号。然后,服务器会制定一个回复消息,并将该消息发送到其名为serverSocket的UDP套接字中。请注意,这是服务器既用于读取也用于发送的同一个套接字。与客户端情况类似,服务器需要包含此数据报目的地的IP地址和端口号。消息最终到达客户端,客户端从服务器读取消息并关闭套接字。

代码详解

现在,让我们更深入地查看这个示例的细节,逐行查看Python中的客户端和服务器代码。我们已经介绍了很多内容,所以从概念上讲这应该相当容易。

UDP客户端代码:

from socket import *

serverName = 'hostname'
serverPort = 12000
clientSocket = socket(AF_INET, SOCK_DGRAM)
message = input('Input lowercase sentence:')
clientSocket.sendto(message.encode(), (serverName, serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print(modifiedMessage.decode())
clientSocket.close()

我们的客户端首先导入Python的socket模块。通过包含这一行,我们将能够使用所有与套接字相关的Python方法。我们在此指定服务器名称和服务器的端口号,然后在客户端创建UDP套接字。客户端从屏幕获取一些用户输入,并使用sendto方法将应用层消息发送到客户端的套接字。你可以看到服务器名称(实际上是其IP地址)和服务器的端口号是如何包含在对sendto方法的调用中的。服务器名称到服务器IP地址的转换实际上在sendto方法内部为你完成,当然这会涉及对DNS的调用。然后,客户端使用recvfrom方法从服务器读取回复。请注意,这里指定了要接收的套接字clientSocketrecvfrom方法返回消息和发送此消息的IP地址。客户端然后打印消息,并通过调用close方法关闭套接字。

UDP服务器代码:

from socket import *

serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('', serverPort))
print("The server is ready to receive")
while True:
    message, clientAddress = serverSocket.recvfrom(2048)
    modifiedMessage = message.decode().upper()
    serverSocket.sendto(modifiedMessage.encode(), clientAddress)

与客户端一样,服务器首先导入Python的socket模块,然后使用socket方法创建一个名为serverSocket的UDP套接字。然而,在服务器的情况下,服务器不希望其操作系统为这个套接字分配任意旧的端口号,因为客户端将专门在服务器端口12000上联系服务器。所以在这里,服务器使用bind方法将端口号12000分配给这个套接字。如果端口号12000已被另一个进程使用,bind方法将在此返回一个错误条件。然后,服务器进入一个循环,使用我们在客户端见过的recvfrom方法从套接字读取数据,执行其转换为大写的操作,然后通过调用sendto方法返回回复。

TCP套接字编程 🔄

上一节我们介绍了UDP套接字编程,本节我们来看看TCP套接字。TCP套接字是面向连接的,这意味着客户端和服务器在实际开始传输数据之前需要先进行一些通信。因此,客户端将首先联系服务器,这意味着服务器必须已经启动并运行,并且必须已经打开了一个欢迎套接字,等待客户端的联系。在客户端,客户端将创建一个套接字,指定服务器的IP地址以及服务器的端口号。当该套接字被创建时,神奇的事情就发生了:客户端进程在TCP层面联系服务器进程以建立连接。

关于TCP套接字,最重要的一点是,当客户端首次联系服务器作为TCP握手的一部分时,服务器将创建一个专门用于与该特定客户端通信的新套接字。我发现第一次接触TCP套接字的学生有时(实际上可能经常)会混淆这里涉及的两个套接字。所以请仔细思考。首先,有一个欢迎套接字。这是所有希望与服务器在特定端口号(例如Web服务器的端口80)上通信的客户端的初始联系点。其次,有一个由服务器创建的、用于未来与该特定客户端通信的新套接字。

你可能会问,这个新套接字关联的端口号是多少?目前答案可能有些令人困惑:新套接字与初始欢迎套接字具有相同的端口号。当我们稍后在第三章开头讨论多路复用和解复用时,会澄清这一点。现在,只需记住,每次TCP客户端首次联系TCP服务器时都会创建一个新套接字,并且这个新套接字在该TCP连接持续期间专门用于与该特定客户端通信。这个TCP连接就像是客户端和服务器之间的一条管道,管道的服务器端就是这个新创建的套接字。正如我们所看到的,这条管道在客户端和服务器进程之间提供了可靠的、有序的字节流传输。

TCP客户端-服务器交互

现在,让我们回到我们简单的客户端-服务器应用程序,像处理UDP一样,看看TCP客户端和TCP服务器之间的交互。请记住,与UDP不同,TCP是面向连接的服务。这意味着在客户端和服务器可以相互发送应用层消息之前,它们首先需要握手并建立TCP连接。TCP连接的一端将连接到客户端TCP套接字,另一端将连接到服务器端TCP套接字。这次让我们从服务器端开始,因为服务器需要启动并运行,并等待客户端的连接请求。

服务器首先创建一个套接字,它将在此套接字上等待来自TCP客户端的传入连接请求。这是欢迎套接字,有时也称为监听套接字。它是服务器等待初始客户端联系的套接字,但它不是客户端和服务器之间应用层消息流动所通过的套接字。

创建套接字后,服务器然后在此欢迎套接字上调用accept方法。这是一个阻塞调用。它将导致服务器等待,直到有客户端联系它。

现在,让我们转到客户端。客户端也创建一个TCP套接字,指定服务器的名称和服务器端口号,该套接字将连接到这个端口。在客户端创建套接字将导致从客户端向服务器发送一个TCP连接请求消息。这个连接请求消息是从传输层内部发送的,当客户端调用socket方法时。它不是由应用程序本身发送的。

来自客户端的这个连接请求正是服务器一直在等待的。当它在服务器端被接收时,会发生几件重要的事情。首先,在服务器端创建一个新套接字,并返回给服务器端应用程序,该应用程序从它在accept调用上的等待中返回。在这个例子中,这个返回的新创建的套接字称为connectionSocket。这是服务器端应用程序将用于与客户端应用程序通信的套接字。其次,从服务器操作系统内部(再次强调,不是由服务器端应用程序本身)向客户端发送一个TCP级别的消息,让TCP客户端知道连接已建立。

在我们的应用程序中,客户端和服务器然后交换消息,与UDP示例的情况非常相似。但让我最后一次强调,服务器端应用程序使用这个新创建的套接字(从accept返回时创建的)与客户端通信,而不是使用监听套接字。客户端将使用它之前创建的客户端套接字与服务器通信。这是它创建的唯一套接字。

代码详解

现在,让我们看看使用TCP套接字的应用程序客户端的Python代码。

TCP客户端代码:

from socket import *

serverName = 'hostname'
serverPort = 12000
clientSocket = socket(AF_INET, SOCK_STREAM)
clientSocket.connect((serverName, serverPort))
sentence = input('Input lowercase sentence:')
clientSocket.send(sentence.encode())
modifiedSentence = clientSocket.recv(1024)
print('From Server:', modifiedSentence.decode())
clientSocket.close()

我们的基于TCP的客户端同样首先导入Python的socket模块。在此指定服务器名称和服务器端口号。然后通过调用socket方法在客户端创建TCP套接字。请注意,此处socket方法的参数指定这是一个IPv4套接字,SOCK_STREAM表示要创建一个TCP套接字。在向服务器发送消息之前,基于TCP的客户端必须首先通过调用套接字上的connect方法来连接到服务器,指定要连接的服务器。从connect方法调用返回后,连接就已建立。所有底层的握手都已经发生。然后,客户端可以从键盘读取输入,并使用此处的send方法将输入发送到客户端。请注意,在这种TCP情况下,无需通过send方法的调用包含关于消息发送给谁的信息。连接已经建立,所以我们知道连接的另一端是谁。然后,客户端通过recv方法接收服务器的回复,显示消息并退出,关闭套接字。

TCP服务器代码:

from socket import *

serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('', serverPort))
serverSocket.listen(1)
print('The server is ready to receive')
while True:
    connectionSocket, addr = serverSocket.accept()
    sentence = connectionSocket.recv(1024).decode()
    capitalizedSentence = sentence.upper()
    connectionSocket.send(capitalizedSentence.encode())
    connectionSocket.close()

通过这里的socket方法调用,我们创建了一个互联网IPv4流套接字,也就是TCP套接字。我们将该套接字绑定到端口12000。然后,我们通过listen(1)将套接字设置为监听模式。现在我们准备好接收客户端连接请求,然后进入一个循环。每次循环,我们连接到一个客户端,完成工作,关闭连接,然后循环回来等待另一个客户端连接请求。

你需要关注的最重要的一行是这里我们调用accept方法的这一行。这是服务器将在accept方法内等待直到客户端连接的地方。从accept返回后,操作系统为我们创建了一个新套接字,这里称为connectionSocket。这个新套接字将是用于与客户端通信的套接字。此时,服务器现在有两个套接字:一个欢迎套接字和一个为与此特定客户端通信而创建的套接字。获取新的连接套接字后,服务器从客户端读取一行,完成其工作,将大写句子发送回客户端,然后关闭连接套接字。请注意,当服务器在此处调用send方法时,它使用的是连接套接字,而不是欢迎套接字来与客户端通信。

总结 📝

本节课中我们一起学习了套接字编程。我们学习了套接字抽象,学习了如何编程UDP套接字和TCP套接字,甚至通过一个使用套接字编程的非常简单的客户端-服务器应用程序的Python代码示例进行了逐步讲解。我们对套接字的讨论也结束了对应用层的整体讨论。

我们对应用层的研究现已完成,我们学到了大量的知识。我们首先讨论了构建应用程序的两种基本方式:客户端-服务器范式和对等范式。然后我们讨论了应用需求:是否有延迟要求、可靠数据传输要求?应用程序是否需要一定量的带宽才能成功?接着我们讨论了传输层向应用程序提供的两种服务类型:TCP提供可靠的、流量控制的、拥塞控制的、面向字节流的数据传输方法;UDP服务模型则提供不可靠的、面向数据报的服务。我们学习了应用层协议,并研究了特定的互联网应用层协议,包括用于Web的HTTP、用于电子邮件的SMTP、提供关键互联网基础设施服务的域名服务DNS(但它本身作为一个应用运行),以及快速浏览了对等网络,特别是BitTorrent系统。然后我们转向视频流,研究了一个具有时序考虑的应用程序,并研究了内容分发网络CDN,这些是用于在用户所在的网络边缘附近提供内容的大规模分布式系统。最后,我们学习了套接字编程。套接字是互联网中应用代码与其下层传输层之间的API。我们学习了套接字抽象,以及使用UDP套接字和TCP套接字编程分布式应用程序的具体细节。

也许最重要的是,我们学习了协议。我们看到了许多客户端-服务器协议的例子,其中客户端发出请求,服务器用数据(通常还带有状态码)回应请求。我们还查看了协议消息的格式,发现我们查看的每条消息都有一个头部部分(包含关于消息本身的信息)和一个数据或消息的有效载荷部分。在我们对网络应用和应用层协议的研究中,我们看到了一些跨越所有应用和应用层协议的重要主题:应用是采用集中式还是分散式方法?应用和协议是无状态的还是有状态的?规模问题如何解决?如何在拥有数亿个交互端点的互联网规模上运行?应用程序是否总是需要可靠的数据传输,或者不可靠的消息传输实际上就足够了?最后,我们在许多情况下看到了将复杂性推向网络边缘(即网络边缘的主机,而不是网络深处的路由器和交换机)的概念。

这确实结束了我们对应用层的讨论。接下来,我们将深入传输层。

3.1:传输层服务简介

在本节课中,我们将开始学习计算机网络体系结构中的传输层。我们将了解传输层提供的核心服务、其基本工作原理,并初步认识互联网中两个主要的传输协议:TCP和UDP。

概述

在完成了应用层的学习后,我们现在将深入传输层。传输层是互联网架构的关键组成部分之一。我们将在此探讨几个根本性的重要挑战:如何在可能损坏或丢失消息的信道上实现可靠通信;如何让分布式实体同步共享状态;以及如何让多个通信实体调整其通信速率,以避免某些实体溢出并耗尽网络资源。当然,我们也将研究当今互联网上可用的两个主要传输协议:UDP和TCP。

学习方法

我们的方法,一如既往,是从基本原理开始。我们将探讨如何实现复用解复用可靠数据传输以及流量与拥塞控制。我们将首先研究这些服务实现背后的原理。

在学习了基本原理之后,我们将观察这些原理是如何具体体现在互联网传输协议中的。这里我们将研究两个协议:UDP,它在通信进程间提供无连接的、尽力而为的服务;以及TCP,它提供可靠的、流量控制的和拥塞控制的、面向连接的传输服务。

传输层服务与协议概览

接下来,让我们退一步,从宏观视角审视传输服务与协议。这里有三个要点需要讨论:

  1. 运行在不同主机上的应用进程之间的逻辑通信概念。
  2. 传输协议本身,以及发送方和接收方各自采取的行动。
  3. 互联网上可供应用程序使用的两个传输协议:TCPUDP

逻辑通信

首先,让我们深入探讨逻辑通信这个概念。从传输层的角度来看,通信的双方——发送方和接收方——在逻辑上是通过一条直接的链路连接在一起的。实际上,主机可能位于地球的两端,被许多不同的网络、路由器和链路分隔。但从逻辑角度看,我们可以想象发送方和接收方是直接相连的。

连接它们的媒介,即它们通信的信道,实际上可能会丢失消息、重排消息顺序或使消息中的比特位发生翻转。但我们将抽象掉位于这两个通信进程之间的一切,只关注连接它们的那个信道的特性,以及它们如何根据该信道的特性来实现服务。

进程通信与主机通信的区别

我们讨论了运行在不同主机上的进程之间的逻辑通信。通信进程通信主机之间的区别是一个重要的概念,因为它触及了传输层和网络层之间的根本区别以及它们各自提供的服务。

以下是一个可能有用的类比:想象有两栋房子,每栋房子里住着12个孩子。一栋是安妮的房子,另一栋是比尔的房子。我们可以将互联网主机比作房子,而进程就是房子里的孩子。每个主机中运行着许多进程,就像每栋房子里住着许多孩子。

进程之间交换的应用层消息可以看作是装在信封里的信件,这些信封在房子之间传递。现在,想想当一封信到达一栋房子(比如安妮的房子)时会发生什么。安妮必须拿到那封信,并将其递送给她的一个孩子。类似地,当一个数据报到达一台互联网主机时,该主机需要能够将该数据报向上传递给适当的进程,就像安妮将到达的信件分发给她的一个孩子。

网络层协议相当于邮政服务。邮政服务的职责仅仅是在房子之间递送信件。房子内部发生的事情(即把消息分发给正确的孩子)是传输层的职责。将消息从一栋房子送到另一栋房子是邮政服务或网络层的职责。

希望这个类比能清楚地说明网络层和传输层各自的功能区别。这就是我们所说的实体间逻辑通信的含义。

传输层发送方与接收方的行动

接下来,让我们看看传输层发送方或接收方采取的行动,然后我们将快速浏览一下UDP和TCP传输协议,稍后我们会深入介绍它们。

让我们通过一个动画来观察发送方和接收方在传输层的行动。首先从发送方开始。

正如我们在第2章学习应用层时所看到的,一切始于一个应用层进程创建一条消息,并将该消息放入套接字。套接字的下层就是传输层。传输层将获取该应用层消息,确定需要在传输层段的某些头部字段中填入什么信息,创建该段,然后将其向下传递给网络层(在互联网中就是IP协议)。网络层(互联网协议)的职责是实际将该IP数据报从发送主机传送到接收主机。

现在让我们看看接收方会发生什么。接收方的传输层将从网络层接收到段。然后,我们需要检查某些头部字段的值(例如,以确保段未被损坏),提取应用层消息,然后将该消息解复用到适当的应用层套接字。

互联网传输协议:TCP与UDP

让我们通过快速浏览TCP和UDP协议来结束本节。

TCP,即传输控制协议,将在应用层进程之间提供可靠的、按序的交付。我们还将看到,这种交付受到拥塞控制流量控制的约束。为了实现可靠性、拥塞控制和流量控制,我们需要在发送方和接收方建立连接并维护连接状态,我们稍后将研究这是如何实现的。

另一个互联网传输协议当然是UDP,即用户数据报协议。这实际上是一种尽力而为的、朴实无华的协议方法。它提供不可靠的交付,消息可能失序到达,因此正如我们将看到的,它做的事情不多。

互联网未提供的服务

你可能想思考一下,互联网实际上通过这些传输协议没有提供哪些类型的服务。例如,没有服务能保证消息从进入套接字到从另一端弹出之间所花费的时间量。对于像电话呼叫这样的交互式语音应用来说,这可能是一种非常有价值的服务类型。

同样,也没有服务能保证发送方和接收方之间的带宽量。例如,流媒体视频可能希望在发送方和接收方之间获得保证的每秒兆比特吞吐量。你可能也会想象,在传输层能够拥有这样的服务可能非常有价值。

但这两类服务实际上都没有由互联网协议提供。你可能想思考一下,为什么这些不是被提供的服务?这是一个有趣的问题,触及了“什么是服务”以及“为了提供有效的通信,我们真正需要的最少服务量是什么”的核心。

总结

本节课中,我们一起学习了传输层的基本介绍。我们了解了传输层在互联网架构中的关键作用,区分了逻辑通信与物理通信,并通过类比明确了传输层与网络层的职责划分。我们还初步认识了传输层在发送端和接收端的基本操作流程,并介绍了互联网的两个核心传输协议:提供可靠、面向连接服务的TCP,以及提供不可靠、无连接服务的UDP。最后,我们思考了当前互联网传输层未提供的服务类型,为后续深入学习传输层原理和协议细节奠定了基础。接下来,我们将开始深入探讨刚才提到的一些基本原理和技术。

3.2:传输层多路复用与多路分解 🚦

在本节课中,我们将要学习传输层中的两个核心概念:多路复用与多路分解。我们将探讨它们如何工作,以及它们在TCP和UDP协议中的具体实现有何不同。

概述

多路复用与多路分解是计算机网络协议栈各层都存在的通用过程。在传输层,它们负责将来自不同应用程序的数据流正确地导向目的地。简单来说,多路复用是将多个数据流合并到一个信道中,而多路分解则是将合并的数据流分离并导向正确的接收方。

多路分解的基本概念

上一节我们介绍了多路复用与多路分解的基本定义,本节中我们来看看多路分解的具体过程。

想象一台互联网主机,它接收到的数据报携带着发往不同应用程序或不同协议的有效载荷。将这些有效载荷引导至主机内运行的相应应用程序或协议的过程,就是多路分解。多路复用则本质上是其逆过程。

日常生活中的类比

为了更好地理解,我们可以从日常生活中找到类比。

以下是几个常见的例子:

  • 高速公路:多个入口匝道将车辆汇入(多路复用)主干道,而在大型立交桥,车辆又从主干道分流(多路分解)到多个不同的出口匝道。
  • 机场值机:乘客根据舱位等级(商务舱、经济舱)或安检类型(TSA预检、普通通道)被分流到不同的队列,这种根据特定属性被引导至不同服务通道的过程,正是多路分解的核心。

互联网环境下的多路复用与分解

现在,让我们将视角转回互联网环境,具体看看这个过程是如何实现的。

以下是传输层处理多路复用与分解的基本设置:

  • 在发送端主机,进程P1和P2通过各自的套接字向下发送数据。
  • 传输层必须对来自P1和P2的数据进行多路复用,将其放入报文段,并在传输层头部添加用于后续多路分解的信息。
  • 当数据报到达接收端主机时,传输层执行相反的多路分解操作,利用头部信息将接收到的报文段内容递送到正确的套接字。

UDP的多路分解

为了理解UDP这种无连接协议如何进行多路分解,我们需要回顾一下套接字编程的知识。

在创建套接字时,应用程序员必须指定一个本地端口号。例如,在代码 DatagramSocket mySocket = new DatagramSocket(12534); 中,12534 就是指定的本地端口号。

当创建一个要发送的数据报时,必须指定目的地的IP地址和目的端口号。在接收端,主机检查UDP报文段中的目的端口号,并将该报文段导向与该端口号关联的套接字。这就是UDP的多路分解操作。

需要注意的是,在UDP中,即使来自不同源IP地址和源端口号的多个客户端向同一个目的端口号发送数据报,它们也都会被导向接收主机的同一个套接字,因为UDP的多路分解仅基于目的端口号进行。

UDP多路分解示例

让我们通过一个具体例子来加深理解。假设有三个主机,进程P3(端口9157)、进程P4(端口5775)和进程P1(端口6428)相互通信。

以下是通信过程中数据报的端口号变化:

  • P1发送给P3:源端口号为6428(P1的端口),目的端口号为9157(P3的端口)。
  • P3回复P1:源端口号为9157(P3的端口),目的端口号为6428(P1的端口,取自接收到的数据报的源端口号)。

TCP的多路分解

上一节我们了解了UDP相对简单的多路分解机制,本节中我们来看看TCP,它的决策过程更为复杂。

TCP是面向连接的,这意味着我们需要标识发送方和接收方。这不仅仅基于IP地址,还基于发送端口号和接收端口号。因此,一个TCP套接字由一个四元组来标识:(源IP地址,源端口号,目的IP地址,目的端口号)

在进行多路分解时,接收方将使用这个四元组中的所有四个值,将报文段导向正确的套接字。一个服务器可以同时拥有许多TCP套接字,每个套接字由其唯一的四元组标识,并关联一个不同的客户端连接。

TCP多路分解示例

考虑一个Apache HTTP服务器(IP地址B,端口80)同时与两个客户端(主机A-IP地址A,主机C-IP地址C)通信。

以下是发往服务器的三个TCP报文段:

  1. 来自主机A,进程P3(端口9157):(源IP: A, 源端口: 9157, 目的IP: B, 目的端口: 80)
  2. 来自主机C,进程X(端口9157):(源IP: C, 源端口: 9157, 目的IP: B, 目的端口: 80)
  3. 来自主机C,进程Y(端口5775):(源IP: C, 源端口: 5775, 目的IP: B, 目的端口: 80)

虽然这三个报文段的目的端口号都是80,但它们的四元组是唯一的。因此,服务器能够正确地将它们多路分解到不同的服务器端进程(例如P4、P5、P6)进行处理。这与UDP仅基于目的端口号进行分解形成了鲜明对比。

总结

本节课中我们一起学习了传输层的多路复用与多路分解。我们了解到,多路分解是决定将报文段有效载荷递送到哪个套接字的过程;而多路复用则是TCP和UDP从多个套接字收集数据,封装成段,并交付给下层网络层的过程。关键区别在于:UDP的多路分解仅基于目的端口号;而TCP则基于源IP、源端口、目的IP、目的端口组成的四元组。最后,我们认识到多路复用与分解是协议栈各层的通用概念,在后续学习网络层和数据链路层时还会再次遇到。

3.3:无连接传输协议UDP 📡

在本节课中,我们将学习传输层的另一个核心协议——用户数据报协议(UDP)。我们将了解UDP的简单特性、其数据报格式、工作原理,以及它如何通过校验和提供基本的错误检测功能。


上一节我们介绍了传输层的基本概念,本节中我们来看看一个极其简单的传输层协议:UDP。

UDP是一个极其简单、没有多余功能的“骨架”协议。它能如此简单,是因为它只提供尽力而为的服务。UDP发送数据段,并希望它们能到达对端。这些数据段可能会丢失,也可能不按顺序到达。因此,UDP本身不需要做太多工作。

由于这种简单的服务,UDP发送方和接收方之间不需要握手,也不需要共享状态。从这个意义上说,UDP被称为无连接的。此外,每个UDP数据段都将独立于其他所有到达的数据段进行处理。

鉴于UDP如此简单,人们可能会问:为什么首先要有UDP?实际上,这有很多充分的理由。

以下是UDP的几个关键优势:

  • 无连接建立延迟:UDP发送方无需等待任何连接建立过程,可以直接发送数据报。
  • 无连接状态:发送方和接收方之间不维护连接状态,因此协议头相对简单,开销小。
  • 无拥塞控制:UDP发送方可以按自己期望的速度发送数据。即使网络变得拥塞,UDP也能继续工作,而TCP在这方面会遇到更多麻烦。

UDP的这些特性使其适用于某些特定类型的应用。

以下是UDP的典型应用场景:

  • 流媒体应用:这类应用能容忍一定程度的数据丢失,但对传输速率敏感,不能施加过强的拥塞控制。
  • DNS和SNMP:这些协议需要在网络状况不佳或拥塞时仍能运行。
  • 应用层构建可靠性:如果需要可靠传输,可以在UDP之上的应用层实现。这正是我们将在本章后面看到的HTTP/3所采用的方法。

UDP在RFC 768中定义。UDP非常简单,其RFC只有大约三页,是了解互联网协议规范的一个很好的起点。


接下来,我们来看看UDP发送方和接收方的具体操作。让我们从UDP发送方开始。

当应用层将一个应用层消息传递给UDP时,整个过程就开始了。UDP通过填充一组特定的头部字段值,并将来自上层的消息(例如一个SNMP消息)作为有效载荷放入UDP数据段中,从而形成一个UDP数据段。创建好UDP数据段后,UDP将其传递给IP层。IP层接着将该IP数据报转发给接收方的IP主机。

在接收方,UDP接收器从下层网络层接收一个数据段。它会执行UDP校验和检查,提取出应用层消息,然后将该消息解复用到相应的应用层套接字。


虽然查看数据包格式(在这里是UDP数据段格式)可能有些枯燥,但这就像吃蔬菜一样,对你有益。仔细思考,每个头部字段背后都蕴含着许多思想和原理。让我们来看看UDP数据段格式。

UDP数据段的结构非常简单。头部只有四个字段。其中两个字段是源端口号目的端口号,用于我们刚刚学习的复用和解复用。还有一个长度字段,因为应用数据(UDP数据段的有效载荷部分)长度是可变的,UDP需要知道数据段的确切长度。最后一个是校验和字段


我们刚刚在UDP头部遇到的一个字段是互联网校验和字段。现在让我们看看这个字段实际包含什么,以及互联网校验和是如何计算的。这里需要仔细听讲,因为当我们学习TCP和IP协议时,这个概念还会再次出现。

UDP校验和的作用是检测发送方和接收方之间传输的数据段中发生的错误,即比特翻转。可以这样理解:假设我想发送给你两个数字。我发送这两个数字,此外我还发送这两个数字的和。你现在收到三个数字,其中任何一个都可能在传输过程中被改变。你将收到的第一个数字和第二个数字相加,然后检查这个和是否等于我发送给你的校验和。如果不同,你就知道有问题。

UDP发送方和接收方以完全类似的方式工作。在发送方,发送方将UDP数据段的内容(包括UDP头部字段以及数据报的源和目的IP地址)视为一系列16位整数,将它们相加,并取和的反码(我们稍后会详细看)。计算出的校验和值被放入UDP校验和字段,然后将数据段交给IP层。在接收方,接收方再次计算接收到的数据段(同样包括头部和IP地址)的校验和,并检查计算出的校验和是否等于发送方放置在该字段中的值。如果不相等,则表明有错误。如果相等呢?没有检测到错误,但可能仍然存在未被发现的错误吗?我们稍后再讨论。


现在让我们看看互联网校验和是如何实际计算的。假设我们想计算两个16位整数的校验和。实际上,我们会计算更多数据的校验和,但让我们先看一个简单情况。

我们取这里的两个16位整数,将它们相加。从最右边开始:0加1,二进制算术下是1,进位0;1加0是1;1加1是0,进位1;0加0再加进位1是1;0加1是1;1加0是1,依此类推。将16位相加后,我们看到最左边有一个进位1,这会产生回绕。我们将这个进位加回到我们得到的16位和中,得到最终的和。最后,为了计算校验和,我们取反码(即将0翻转为1,1翻转为0),得到这里显示的互联网校验和。

因此,我们看到互联网校验和的计算相对简单。


这里有个问题值得思考:互联网校验和实际上能提供何种程度的比特翻转保护?让我们看一个例子,它能阐明这一点。

假设我们已经计算了之前看到的两个16位整数的校验和。现在想象在传输过程中,第一个数字和第二个数字的某些比特发生了翻转。对于第一个数字,最右边的两个比特“10”翻转为“01”;对于第二个数字,最右边的两个比特“01”翻转为“10”。

你应该能确信,互联网接收方在收到这两个错误的数字后,计算出的校验和将与发送方计算并传输的校验和完全相同。因此,在这种情况下,这些错误未被检测到

我们将在后面学习链路层和安全时看到,实际上有更强大的方法来检测和纠正传输中的比特错误。但这里的要点是:互联网校验和是一种保护形式,但它并非万无一失。


让我们通过总结所学内容来结束对UDP的学习。

我们了解到UDP是一个没有多余功能的协议。使用UDP时,数据段可能会丢失,可能会乱序到达,甚至互联网校验和也不能100%保证检测出比特错误。我们也了解到UDP确实有其用武之地。它的价值在于:由于无需握手或建立连接,不会产生RTT延迟;并且因为没有内置的拥塞控制,UDP即使在网络服务受损(例如网络拥塞或过载)时也能运行。我们还看到,UDP可以通过使用校验和来辅助实现可靠性。

如果这种“尽力而为”的无冗余服务还不够,应用程序员可以始终使用TCP,或者,正如我们之前看到的,应用程序员可以在UDP之上的应用层构建额外的功能。例如,HTTP/3正是这样做的,我们很快就会看到。

本节课中我们一起学习了用户数据报协议。我们了解了UDP发送方和接收方的操作,查看了UDP数据段格式,并研究了互联网校验和。在我们继续学习另一个互联网传输协议TCP之前,我们需要仔细研究一下可靠性:我们如何在一个不可靠的媒介上提供可靠数据传输的机制?因为这正是TCP必须要做的。这就是我们接下来要学习的内容。

3.4:可靠数据传输原理 🎼

在本节课中,我们将学习如何在一个不可靠的网络上构建可靠的数据传输协议,例如TCP。我们将从最简单的假设开始,逐步引入错误检测、确认、序列号和超时重传等核心机制,最终构建一个能够应对数据包损坏和丢失的可靠传输协议。


概述

可靠数据传输协议的目标是,在底层网络可能损坏、丢失或重排数据包的情况下,为上层应用提供一条仿佛直接相连的可靠逻辑信道。这需要发送方和接收方通过交换控制信息来协同工作。

为了实现这一目标,我们将定义一个简单的协议框架,称为RDT。该框架包含以下核心接口:

  • 发送方:应用层调用 rdt_send(data),协议层调用 udt_send(packet) 通过不可靠信道发送。
  • 接收方:网络层调用 rdt_rcv(packet),协议层调用 deliver_data(data) 将数据递交给应用层。

我们将使用有限状态机来描述协议双方的行为,并假设数据单向流动,但控制信息可以双向传递。


RDT 1.0:完全可靠信道下的传输

上一节我们介绍了协议的基本框架。本节中,我们首先来看一个最简单的情况:假设底层信道是完全可靠的,不会发生比特错误、丢包或乱序。

在这种情况下,协议的工作非常简单。以下是发送方和接收方的状态机描述:

发送方状态机:

  • 状态: 等待上层调用 (wait for call from above)
  • 事件: rdt_send(data) 被调用。
  • 动作: 将数据打包成报文,通过 udt_send(packet) 发送。然后返回“等待上层调用”状态。

接收方状态机:

  • 状态: 等待下层调用 (wait for call from below)
  • 事件: rdt_rcv(packet) 被调用。
  • 动作: 从报文中提取数据,通过 deliver_data(data) 递交给上层应用。然后返回“等待下层调用”状态。

这个版本虽然简单,但为我们展示了协议的基本结构:两端各自维护一个状态机,通过事件触发状态转移和动作。


RDT 2.0:具有比特差错信道的传输

上一节我们假设了完美的信道。本节中,我们引入一个更现实的假设:底层信道可能损坏数据包中的比特,但不会丢包或乱序。

为了从比特差错中恢复,我们需要两个新机制:

  1. 差错检测:接收方使用校验和(如互联网校验和)来检测报文是否损坏。
  2. 反馈机制:接收方必须向发送方提供明确的反馈。

以下是实现反馈的两种控制报文:

  • 肯定确认:接收方收到完好的数据包后,发送 ACK
  • 否定确认:接收方检测到损坏的数据包后,发送 NAK

发送方根据反馈采取行动:

  • 收到 ACK:发送下一个数据包。
  • 收到 NAK:重传上一个数据包。

这种“发送-等待-确认”的模式被称为停等协议

以下是RDT 2.0的状态机描述:

发送方状态机:

  • 状态1: 等待上层调用 (wait for call from above)
    • 事件: rdt_send(data)
    • 动作: 创建带校验和的报文并发送。转入状态2
  • 状态2: 等待ACK或NAK (wait for ACK or NAK)
    • 事件: 收到 ACK
    • 动作: 返回状态1
    • 事件: 收到 NAK
    • 动作: 重传上一个报文。保持在状态2

接收方状态机:

  • 状态: 等待下层调用 (wait for call from below)
    • 事件: rdt_rcv(packet),且报文损坏
    • 动作: 发送 NAK。丢弃报文。
    • 事件: rdt_rcv(packet),且报文完好
    • 动作: 发送 ACK。提取并递交数据 (deliver_data)。

这个协议存在一个关键缺陷:ACKNAK 报文本身也可能在传输中被损坏。发送方无法区分损坏的反馈报文,这可能导致进程停滞或数据重复。


RDT 2.1:处理损坏的确认

上一节我们遗留了确认报文损坏的问题。本节中,我们通过引入序列号来解决它。

由于是停等协议,同一时刻只有一个报文在传输中。因此,我们只需要一个1比特的序列号(0或1)就足以区分当前报文和重传报文。

发送方在报文中加入序列号。接收方在发送 ACKNAK 时,也指明所确认的序列号。这样,即使确认报文损坏,发送方也能通过后续接收到的报文推断出之前的状态。

以下是协议的核心改进:

  • 发送方和接收方各增加一个状态,分别跟踪期望发送或接收的序列号。
  • 接收方如果收到损坏的报文序列号错误的完好报文,会重发上一次的 ACK(即对已正确接收的最后一个报文的确认)。

通过这种方式,我们消除了对 NAK 的绝对依赖,协议演变为主要依靠 ACK 和序列号来运作。


RDT 2.2:无NAK的确认协议

上一节的协议已经足够健壮。本节中,我们做一个简化:完全取消 NAK,只使用带序列号的 ACK

具体操作如下:

  • 接收方收到损坏的报文或序列号错误的报文时,不发送 NAK,而是重复发送对上一个已正确接收报文的 ACK
  • 发送方如果收到重复的 ACK(例如,期待 ACK1 却收到了 ACK0),则知道接收方没有正确收到当前报文,于是触发重传。

这种“收到重复ACK即触发重传”的机制,与 TCP 协议中使用的快速重传 思想非常相似。


RDT 3.0:具有比特差错和丢包信道的传输

到目前为止,我们假设信道只损坏数据但不丢失。本节中,我们面对最现实的情况:信道既可能损坏数据包,也可能完全丢失数据包或确认报文。

为了解决丢包问题,我们引入最后一个关键机制:超时重传

核心思想: 发送方在发送一个数据包后启动一个定时器。如果在合理的时间内没有收到对应的 ACK,就认为数据包或 ACK 已丢失,并重传该数据包。

这里的关键是确定“合理的”超时时间。时间太短会导致不必要的重传(假性超时),降低效率;时间太长则会在丢包后等待过久,同样降低性能。

以下是RDT 3.0发送方状态机的关键修改:

  • 在“发送报文”的动作中,启动定时器
  • 在“等待ACK”的状态中,增加一个新事件:定时器超时 (timeout)
  • 超时事件的动作: 重传数据包,并重启定时器。
  • 正确收到 ACK 后,停止定时器

接收方的逻辑与RDT 2.2相同,依靠序列号来识别和丢弃重复的数据包。

运行示例:

  1. 数据包丢失: 发送方超时后重传。
  2. ACK丢失: 发送方超时后重传数据包,接收方通过序列号识别并丢弃重复包,同时再次发送 ACK
  3. 延迟过大(非丢失): 发送方在延迟的 ACK 到达前超时并重传,导致接收方收到重复包。但序列号机制确保了应用层数据不会重复。


总结

本节课中,我们一起学习了构建可靠数据传输协议的核心原理。我们从最简单的理想信道(RDT 1.0)出发,逐步增加了应对现实网络挑战的能力:

  1. RDT 2.0:引入校验和、ACKNAK,处理比特差错
  2. RDT 2.1/2.2:引入1比特序列号,处理损坏的确认报文,并过渡到无 NAK 的确认机制。
  3. RDT 3.0:引入超时重传机制,最终能够处理比特差错和丢包

我们构建的RDT 3.0是一个功能完整的停等协议,但其性能较低,因为发送方在大部分时间都在等待。在接下来的课程中,我们将分析其性能,并探讨如何通过流水线技术来提升效率,这正是现代协议(如TCP)所做的。

3.4.2:可靠数据传输原理(第一部分)🚀

在本节课中,我们将要学习计算机网络中最核心的挑战之一:如何让两个分布式的实体,通过一个本身不可靠的、可能丢失、损坏或重排消息的信道,进行可靠的通信。我们将从一个简单的、完美的信道模型开始,逐步引入更现实的假设,并探索应对这些问题的协议机制。

场景与抽象

我们考虑一个场景:一个发送进程希望通过一个可靠的信道向一个接收进程发送数据。这里,可靠信道是单向的抽象。

然而,这个抽象的实现位于传输层。实现形式是一个可靠数据传输协议,它包含发送端和接收端。这两个协议实体通过底层的不可靠信道进行双向通信。发送端向接收端发送数据,接收端则向发送端回复控制信息。

在开发协议时,需要牢记以下几点:

  • 协议的复杂度高度依赖于底层不可靠信道的特性(是否会丢包、损坏、重排序)。
  • 发送端和接收端彼此无法直接感知对方的状态或信道中发生的情况。它们只能通过发送和接收消息来了解彼此。

协议接口

在深入协议之前,我们先明确传输层可用的接口。

在发送端,应用层进程通过调用 rdt_send() 将数据传递给传输层。传输层将数据添加头部,构成传输层报文段,然后通过 udt_send() 将其发送到不可靠信道。

在接收端,当报文段从信道到达时,传输层通过 rdt_rcv() 接收。如果报文段无误,接收端会提取数据,并通过 deliver_data() 将其递交给上层应用进程。协议的目标是确保发送端下发的每一份数据,都能恰好一次、按序地交付给接收进程。

协议规范:有限状态机

我们需要一种方法来规范地描述协议。这里我们采用有限状态机

有限状态机的核心概念是状态。一个实体(如发送方)在特定时刻处于某个状态。状态之间会发生转移,转移由事件触发,并可能伴随特定的动作

以一个电灯开关为例:

  • 状态
  • 事件:按下“开”开关或按下“关”开关。
  • 动作:发光或停止发光。
  • 转移:当灯处于状态时,发生“按下开开关”事件,则转移到状态并执行“发光”动作。

RDT 1.0:完全可靠信道上的协议

我们从最简单的情况开始:底层信道是完美的,不会丢失、损坏、重复或重排序报文。

以下是发送方和接收方的有限状态机描述。

发送方 (RDT 1.0)

  • 只有一个状态:等待上层调用
  • 事件:rdt_send(data) 被调用(数据从应用层传来)。
  • 动作:创建包含数据的报文段,调用 udt_send(packet) 将其发送到信道。
  • 转移:保持在原状态。

接收方 (RDT 1.0)

  • 只有一个状态:等待下层调用
  • 事件:rdt_rcv(packet) 被调用(报文从信道到达)。
  • 动作:从报文段中提取数据 data,调用 deliver_data(data) 将数据递交给上层应用。
  • 转移:保持在原状态。

RDT 1.0 协议极其简单,因为信道本身是可靠的。但当信道存在缺陷时,发送方和接收方就需要做更多工作。

RDT 2.0:具有比特差错信道的协议

现在考虑一种更现实的情况:信道可能翻转报文中的比特位,导致接收方收到损坏的数据。

人类在可靠通信中会使用一些机制,例如:

  • 肯定确认:接收方明确告知发送方“我收到了你的消息”。
  • 否定确认:接收方告知发送方“我收到了,但消息有误”。
  • 重传:发送方重新发送未被正确接收的消息。

RDT 2.0 协议将采用这些机制。它使用校验和来检测比特差错,并采用停等方式工作:发送方发送一个报文后,会等待接收方的响应。

以下是 RDT 2.0 的有限状态机描述。

发送方 (RDT 2.0)

  • 状态1:等待上层调用
    • 事件:rdt_send(data) 被调用。
    • 动作:创建报文 sndpkt(含校验和),调用 udt_send(sndpkt) 发送。然后转移到“等待ACK或NAK”状态。
  • 状态2:等待ACK或NAK
    • 事件1:收到 rdt_rcv(rcvpkt)isACK(rcvpkt) 为真。
      • 动作:转移到“等待上层调用”状态。
    • 事件2:收到 rdt_rcv(rcvpkt)isNAK(rcvpkt) 为真。
      • 动作:调用 udt_send(sndpkt) 重传上一个报文。保持在本状态。

接收方 (RDT 2.0)

  • 状态:等待下层调用
    • 事件1:收到 rdt_rcv(rcvpkt)corrupt(rcvpkt) 为真(报文损坏)。
      • 动作:创建NAK报文,调用 udt_send(NAK) 发送给发送方。
    • 事件2:收到 rdt_rcv(rcvpkt)not corrupt(rcvpkt) 为真(报文完好)。
      • 动作:提取数据,调用 deliver_data(data) 递交给上层。创建ACK报文,调用 udt_send(ACK) 发送给发送方。

RDT 2.0 运行示例

  1. 无差错情况:发送方发送报文 -> 接收方收到完好报文,回ACK -> 发送方收到ACK,准备发送下一个数据。
  2. 有差错情况:发送方发送报文 -> 接收方收到损坏报文,回NAK -> 发送方收到NAK,重传报文 -> 接收方收到完好报文,回ACK -> 发送方收到ACK,准备发送下一个数据。

RDT 2.0 的缺陷与改进

RDT 2.0 有一个致命缺陷:如果ACK或NAK报文本身在传输中被损坏了怎么办?发送方收到一个损坏的反馈分组,它无法知道接收方之前是否正确收到了数据分组。

如果发送方简单地重传,可能导致接收方收到两个相同的、完好的数据分组,并将其当作两份独立数据交付给上层,这是错误的。

解决方案是:发送方在收到损坏的ACK/NAK时也进行重传,但同时为每个数据分组添加一个序号。接收方可以通过序号来发现重复的分组并丢弃它。

由此我们得到 RDT 2.1 协议。

RDT 2.1:应对ACK/NAK损坏

RDT 2.1 是一个停等协议,使用 1比特序号(0或1)。发送方和接收方的状态数都增加了,因为需要记住当前期待的是序号0还是序号1的分组。

发送方 (RDT 2.1) 有四个状态,分别对应“等待发送序号0/1”和“等待序号0/1的ACK”。
接收方 (RDT 2.1) 有两个状态,分别对应“期待接收序号0”和“期待接收序号1”。

其核心逻辑是:

  • 发送方为每个数据包附加当前序号。
  • 接收方检查到达的包:
    • 如果序号符合预期且完好,则交付数据,回送ACK。
    • 如果序号符合预期但损坏,则回送NAK。
    • 如果序号不符合预期(例如收到旧的重复包),则也回送ACK(告知发送方这个旧包已收到,可以清除了),但不交付数据给上层

这样,无论数据包还是ACK/NAK包受损,协议都能正确工作。甚至可以设计一个只使用ACK的版本(RDT 2.2),其原理类似。

本节总结

本节课中,我们一起学习了如何在可能发生比特差错的信道上实现可靠数据传输。我们从一个完美的信道模型(RDT 1.0)开始,逐步引入了更现实的假设。

我们探讨了以下核心机制:

  1. 差错检测:使用校验和 (corrupt(rcvpkt)) 来检测比特错误。
  2. 接收方反馈:使用肯定确认 (ACK) 和否定确认 (NAK)。
  3. 重传:当检测到差错或收到NAK时,发送方执行重传 (udt_send(sndpkt))。
  4. 序号:使用1比特序号来区分新旧数据包,防止重复交付。

通过这些机制的组合(RDT 2.1),我们能够在一个双向都可能出现比特差错的信道上实现可靠的单向数据传输。

然而,还有一个关键问题尚未解决:如果数据包或确认包在整个传输过程中丢失了,又会发生什么?这将是下一节要讨论的内容。

3.5:可靠数据传输协议的性能分析 🚀

在本节课中,我们将要学习可靠数据传输协议的性能表现。我们将重点分析“停止-等待”协议的局限性,并探讨两种提升性能的流水线协议:“回退N步”和“选择重传”。理解这些协议如何工作以及它们之间的权衡,是掌握现代网络传输层(如TCP)工作原理的基础。


协议设计对性能的影响

在本课程中,你已经看到协议设计能对性能产生显著影响的例子。其中一个例子是HTTP 1.0,它每次请求都必须建立一个新的TCP连接。这在HTTP 1.1中得到了改进,允许后续请求复用同一个TCP连接。

在传输层,我们也会看到类似的情况。上一节我们讨论了用于可靠数据传输的“停止-等待”协议的设计。本节中,我们来评估它的性能。

我们将从利用率的角度进行评估。利用率是指发送方能够利用其所连接链路带宽的时间比例。对于一个理想协议,利用率应为1。

为了具体说明,我们来看一个1 Gbps的链路,其传播延迟为15毫秒。我们发送8000比特(即1000字节)的数据包。每个数据包的传输延迟为8微秒(即0.008毫秒)。仅从单位上看,传输延迟相对于传播延迟来说极其微小。


“停止-等待”协议的性能分析

现在,让我们在时间序列图上画出“停止-等待”协议的操作。

我们看到,发送方花费一小段时间传输数据包,然后花费大量时间等待数据包传播到接收方,并等待确认信息传播回发送方。

因此,我们的利用率可以根据往返时间(RTT)和数据包长度(除以速率得到传输延迟)来计算。公式如下:

利用率 = 传输延迟 / (传输延迟 + 往返时间)

代入之前的数值,我们得到大约8微秒除以30毫秒。结果是一个极小的利用率。实际上,如果我们使用之前提到的1 Gbps链路,有效利用率只有约33 Kbps。

所以,虽然“停止-等待”协议是完全可靠的,但其性能很差。它成为了性能的瓶颈,即使主机拥有配置良好的网络连接。

如果我们可视化一条横跨国家的网络连接,会看到一条很长的“管道”,但里面只有一个数据包。


流水线技术:提升性能的解决方案

解决性能问题的方案称为流水线。这允许协议有多个“在途”数据包,从而在概念上填满管道。

在最佳情况下,发送方能够持续背靠背地发送数据包,直到开始收到来自接收方的确认。

让我们看看在时间序列图上,这种提升的利用率是如何工作的。

现在,发送方能够持续背靠背地发送数据包(本例中窗口大小为3个包)。当这些数据包到达接收方时,接收方开始发回确认。当发送方收到这些确认后,它就能再发送3个数据包。因此,在相同的时间段内,我们能够发送三倍的数据量,这意味着我们的利用率提高了三倍。


流水线协议的实现方式

流水线增加了可靠数据传输协议的复杂性,有几种不同的实现方式。其中一种称为回退N步

在GBN协议中,发送方允许在收到确认前,最多有N个数据包在途。为了跟踪这些数据包,每个数据包的头部需要一个序列号,我们之前使用的1比特序列号不再够用。因此,我们需要在头部预留一些比特来跟踪序列号。

以下是发送方缓冲区的可视化:

  • 已确认:一些已被确认的数据包。
  • 发送窗口:一些已发送但未确认的数据包(在途),以及一些可以发送更多数据包的空位。
  • 未来位置:一些尚不可用的数据包位置,因为它们超出了当前窗口。

在GBN算法中,使用累积确认。ACK确认所有直到该序列号的数据包。当一个ACK到达时,窗口向前移动到N+1的位置。

发送方必须为最旧的“在途”数据包维护一个计时器。如果确认没有到达,数据包可以被重传。如果发生超时,发送方将“回退N步”,即回到其窗口的起始处,并按顺序重新传输所有数据包。


“回退N步”的接收方行为

在接收方一侧,ACK按序发送给接收到的最高序列号。

如果数据包乱序到达,接收方只是持续确认它最后按序接收到的序列号。这些乱序的数据包可能会被丢弃,因为接收方知道,如果较早的数据包超时,发送方将不得不回退并重传它们。

另一方面,数据包可能只是延迟到达导致乱序,因此接收方可以选择缓冲这些乱序的数据包,以防较早的数据包稍后到达。

在接收方的缓冲区中,我们会看到接收基序号,这是接收方将接受的数据包窗口的起始。低于此序号的序列号已被确认,而高于此序号到达的则是乱序数据包。


“回退N步”协议示例分析

现在,让我们在时间序列图上查看GBN算法。

发送方初始窗口大小为4个数据包,它发送出前4个包(0到3)。但数据包2在途中丢失了。

当数据包到达时,接收方发回确认。但请注意,当数据包3到达时,接收方发送了一个针对数据包1的重复ACK,因为它只确认按序到达的数据包。

当发送方收到这些ACK时,它能够移动其窗口并发送更多数据包。这在最初几个ACK到达时发生,但第三个ACK是重复的,因此对窗口没有影响。在接收方一侧,它丢弃这些乱序数据包,并持续发回针对数据包1的重复ACK。

最终,数据包2的ACK超时,发送方重传整个窗口(从数据包2开始)。由于这些数据包按序到达,接收方确认所有数据包。

你可能会注意到这里存在一些低效之处,即重传了接收方已经接收到的数据。这是由于在算法复杂性和带宽效率之间做出的工程权衡。在这些协议被开发时,主机的计算和内存资源远比今天稀缺,因此这些协议被优化为需要尽可能少的指针和计时器。


另一种流水线协议:选择重传

GBN的替代方案称为选择重传

在SR协议中,接收方单独确认每个数据包,即使是那些乱序到达的数据包。这要求接收方缓冲这些乱序数据包,直到它能够填补空缺,并按序将所有数据交付给应用程序。

在发送方一侧,与仅为最旧数据包维护一个计时器不同,在SR中,发送方需要为它发送的每个数据包维护一个计时器。和之前一样,发送方维护一个允许“在途”的N个数据包的窗口。


“选择重传”的缓冲区管理

现在,我们的SR发送缓冲区可能混合着未确认和已确认的数据包。但窗口只有在最旧的数据包被确认后才能向前移动。

同样,在接收方一侧,我们看到已确认的数据包,后面是期望的数据包窗口,其中一些可能已乱序接收。但同样,窗口只有在按序接收到每个数据包后才会向前移动。

从发送方的角度来看,变化在于增加了多个计时器(每个数据包一个),并且窗口只有在其中最低序列号被确认后才能前进。此时,如果其他数据包已乱序确认,窗口可能需要前进多个位置。

在接收方一侧,我们需要一个乱序数据包缓冲区。每当按序收到一个数据包时,接收方必须检查是否还有其他数据包可以按序交付给应用程序。


“选择重传”协议示例分析

现在让我们在时间序列图上查看SR协议。

和之前一样,窗口大小为N个数据包,发送方首先发送数据包0到3。同样,数据包2丢失,但数据包3到达了。接收方确认数据包3(这次它不发送重复ACK)。

当这些ACK返回到发送方时,它能够移动窗口并发送新数据包。当ACK 3到达时,发送方记录它,但由于仍未收到数据包2的确认,它无法移动窗口。接收方也持续确认乱序数据包。

最终,数据包2的超时到期,发送方重传数据包2。当数据包2到达接收方时,它能够将数据包2到5按序交付给应用程序。当ACK 2返回发送方时,由于它已经记录了乱序的确认,它将能够将窗口向前移动多个位置。


序列号空间与窗口大小的关系

现在让我们看看可能会遇到的一些问题。

请记住,我们必须在数据包头和确认头中跟踪序列号,因此需要为此目的分配一些比特。我们使用的比特越多,每个数据包的头部开销就越大。

在这个例子中,我们使用一个2比特的序列号,允许我们记录0到3的值。假设我们想使用窗口大小为3。发送方发出前三个数据包并相应地移动窗口。在接收方一侧,随着数据包到达,其窗口也移动。假设数据包3丢失,第二个数据包0乱序到达。到目前为止,一切按预期工作,超时将触发数据包3的重传。

现在让我们看一个不同的丢包模式。在这种情况下,前三个数据包到达,接收方的窗口相应移动。然而,所有三个ACK都丢失了。请注意,在互联网中,丢包经常是突发性的,因此这不是一个不现实的场景。

因此,发送方发生的下一个事件是数据包0的计时器超时。当该数据包被重传时,请注意接收方的窗口位置。它期望一个数据包0,但这是比它已经收到的第一个数据包0更晚的一个。因此,虽然到达的数据包0是重复的,但接收方会将其视为新数据,并将这个重复数据包乱序交付给应用程序。

这是一个主要问题,因为我们的可靠传输协议应该提供的保证之一就是按序交付。这展示了我们在上一节中讨论的特性:除了通过控制消息推断外,接收方对发送方的状态是“盲”的。

为了解决这个问题,我们必须建立窗口大小序列号空间之间的关系。事实上,我们需要的序列号空间至少是我们想要使用的窗口大小的两倍。


总结

本节课中,我们一起学习了可靠数据传输协议的性能分析。

我们首先分析了简单的“停止-等待”协议利用率低下的问题,其根本原因在于长传播延迟下,链路带宽未被充分利用。接着,我们引入了流水线技术作为解决方案,它允许多个数据包同时在途,从而显著提高链路利用率。

我们深入探讨了两种主要的流水线协议:

  1. 回退N步:使用累积确认,实现简单,但发生丢包时会重传整个窗口,可能不够高效。
  2. 选择重传:接收方单独确认每个数据包,发送方仅重传丢失的包,效率更高,但需要更复杂的缓冲区管理和更多的计时器。

最后,我们认识到,为了实现正确的按序交付,协议的窗口大小不能超过序列号空间的一半,这是设计可靠协议时必须遵守的关键约束。

这些原理是创建TCP协议的基础,TCP将是我们下一节视频的主题。

3.5.2:TCP的可靠传输、流量控制与连接管理 🔗

在本节中,我们将探讨TCP如何提供可靠的数据传输。我们将看到,TCP使用了我们之前学习过的所有机制:校验和、确认、序列号、超时与重传,以及流水线技术。我们还将研究TCP如何估算发送方与接收方之间的往返时间,并利用该时间设置超时间隔。最后,我们将通过几个场景来观察TCP发送方和接收方的实际运作。

TCP概述 📋

正如我们所见,TCP以点对点方式运行,即在一个发送方和一个接收方之间。其可靠数据传输的语义是有序的字节流,这与我们之前看到的面向消息的UDP形成对比。TCP实现的是一个可靠的字节流抽象。TCP也是全双工的,意味着数据载荷可以在两个方向上流动。

TCP段中承载的数据载荷具有最大段大小,其公式为:

MSS = MTU - (TCP Header Size + IP Header Size)

在实践中,MSS通常为1460字节,但也可能是其他值。

TCP使用类似“回退N步”协议中的累积确认。它是一个流水线协议,同时也是面向连接的,这意味着在数据实际开始流动之前,发送方和接收方之间会进行握手。TCP还具有流量控制功能,这意味着发送方和接收方会进行速度匹配,以防止发送方用数据淹没接收方。

TCP段结构解析 🧩

接下来,让我们看看TCP段的结构。虽然这看起来有些枯燥,字段也很多,但请记住,关键不仅在于了解这些字段是什么,更在于理解它们为何存在。根据我们已经学习的可靠数据传输原理,我们将能够理解TCP为何包含这些字段。

以下是TCP段头部的关键字段:

  • 源端口号与目的端口号:用于多路复用与多路分解。
  • 32位序列号与32位确认号:我们稍后会详细研究。
  • 校验和:与UDP类似,用于错误检测。
  • 选项字段:数量可变,这使得TCP头部长度可变,因此需要一个头部长度字段。
  • RST、SYN、FIN位:用于连接管理。
  • 接收窗口字段:用于流量控制,接收方通过它告知发送方愿意接受的字节数。
  • 拥塞通知位:用于拥塞控制。
  • 紧急指针字段:在实践中很少使用。

序列号与确认号详解 🔢

让我们更深入地探讨TCP序列号和确认号字段的含义。TCP实现的是字节流抽象,TCP段头部携带的序列号表示该段载荷数据中第一个字节的字节流编号确认号由接收方使用,用于告知发送方期望从发送方接收到的下一个字节的序列号。该数字是对该序列号之前所有数据字节的累积确认

关于乱序到达的段,TCP规范没有规定接收方必须如何处理,这由实现者决定。

TCP运行示例 💡

现在,让我们看一个TCP运行的简单示例,观察序列号和确认号。这是一个简单的Telnet场景,主机A向主机B发送一个字符,主机B将该字符回显。

关键点在于:

  • B到A段上的确认号43,比触发该确认的A到B段上的序列号42大1。
  • 类似地,最后一个A到B段上的确认号80,比触发该确认的B到A段上的序列号79大1。

超时间隔的设置 ⏱️

我们已经看到TCP按预期使用了序列号和确认。接下来,让我们探讨一个尚未深入讨论的问题:如何设置超时值?我们来看看TCP是如何做的。

显然,我们希望定时器值依赖于往返时间。但如果设置得太短,会导致过早超时,重传尚未丢失的段。如果等待时间过长,TCP对段丢失的反应又会太慢。

因此,关键问题是如何估算RTT。我们可以测量它:在段发送时启动定时器,在收到该传输的确认时停止定时器,这样就得到了一个采样RTT。但由于采样值可能波动很大,我们需要使用更平滑的采样RTT的平均值

TCP每次获取新的采样RTT时,都会重新计算估算RTT,这个过程称为指数加权移动平均,其公式为:

EstimatedRTT = (1 - α) * EstimatedRTT + α * SampleRTT

其中,α值可以设置以反映最新测量值对估算RTT的影响,典型实现值为0.125。

给定估算RTT后,TCP将超时间隔计算为估算RTT加上一个安全裕量。设置安全裕量的直觉是,如果采样RTT变化很大,我们就需要更大的安全裕量。TCP计算超时间隔的公式为:

TimeoutInterval = EstimatedRTT + 4 * DevRTT

其中,DevRTT是估算RTT偏差的度量,计算为最近测量的采样RTT与当时估算RTT之差的指数加权移动平均。

TCP发送方与接收方行为总结 📝

了解了TCP如何使用序列号、确认和超时机制后,我们现在可以总结TCP发送方和接收方的行为。之后,我们将通过几个场景来观察它们的实际运作。

以下是TCP发送方和接收方操作的大致描述:

TCP发送方事件与动作:

  • 从应用层接收数据:创建带有序列号的段并发送(如果在发送窗口内)。如果定时器未运行,则启动定时器。可以认为只有一个针对最旧未确认段的定时器。
  • 超时:重传导致超时的段,并重启定时器。
  • 收到确认:如果确认了先前未确认的段,则更新已知的确认信息。如果仍有未确认的段在传输中,则重启定时器。

TCP接收方事件与动作:
以下是接收方可能发生的事件以及接收方如何生成确认作为响应:

  • 按序段到达,序列号符合预期:如果到此预期序列号的所有数据已被确认,许多TCP实现会等待最多0.5秒,看是否有另一个按序段到达,然后生成一个覆盖两个段的累积确认,以减少确认流量。
  • 按序段到达,且部分数据待确认:延迟发送确认,等待另一个按序段。
  • 乱序段到达,序列号高于预期:检测到间隙。TCP将发送一个重复确认,指示下一个期望字节的序列号。
  • 到达的段部分或完全填补了接收窗口低端的间隙:接收方将发送一个累积确认,确认迄今为止按序接收的所有数据。

重传场景分析 🔄

为了巩固对TCP可靠性的理解,让我们看几个重传场景。

场景一:确认丢失
一个TCP段被发送,但其确认丢失。在这种情况下,TCP的超时机制导致发送另一个副本,然后由接收方重新确认。

场景二:过早超时
发送两个段并得到确认,但发送方对第一个段发生了过早超时,导致其被重传。需要注意的是,当这个重传段到达时,接收方已经收到了前两个段,因此会重新发送一个针对迄今为止收到的两个段的累积确认,而不仅仅是针对第一个段的确认。

场景三:累积确认的作用
再次发送两个段,第一个确认丢失,但第二个累积确认成功到达发送方。因此,发送方可以继续发送第三个段,因为它知道前两个段已经到达,尽管第一个段的确认丢失了。

TCP快速重传优化 🚀

让我们通过讨论对原始TCP的一项优化——TCP快速重传,来结束对TCP可靠性的研究。请看右侧的示例:发送了五个段,第二个段丢失。接收方会为第一个收到的段生成确认号100。当第三、第四、第五个段到达时,由于第二个段尚未到达,接收方会重复发送确认号100。

发送方看到第一个确认100(这是它期望的),然后又连续收到三个重复的确认100。发送方由此知道出了问题:第一个段到达了,但后续到达的段(正是它们触发了重复确认)虽然被正确接收,但却是乱序的,这意味着接收方在生成这三个重复确认时,检测到了一个缺失的段。

利用快速重传优化,收到三个重复确认会触发发送方立即重传其最旧的未确认段,而无需等待超时事件。这使得TCP能够从很可能发生的丢失事件中更快地恢复。

总结 📚

本节课中,我们一起学习了TCP如何实现可靠数据传输。我们看到,TCP在实践中使用的机制正是我们在可靠数据传输协议中推导出的那些机制。实际上,我们将在学习Web使用的HTTP/3等应用层协议时再次看到这些机制。最后,我们还简要探讨了与可靠数据传输相关的两个主题:流量控制和连接管理。通过理解序列号、确认、超时估算以及快速重传等机制,我们掌握了TCP确保数据在网络中可靠、有序交付的核心原理。

3.5.3:TCP可靠连接机制 🔗

在本节课中,我们将学习TCP(传输控制协议)如何实现面向连接的可靠数据传输。我们将探讨TCP的报文段结构、连接建立、往返时间估计以及其实现可靠数据传输的具体机制。


上一节我们介绍了可靠数据传输的基本原理。本节中,我们来看看TCP如何将这些原理付诸实践。

TCP是一个在多个RFC中定义的协议,经过多年发展和增强,以适应性能提升和网络速度的增长。以下是TCP的一些基本特性:

  • 点对点:仅在两个进程之间通信。
  • 可靠:负责重传丢失或损坏的数据。
  • 字节流:将应用层数据作为字节流交付,不保留消息边界。
  • 全双工:连接两端的进程都可以同时发送和接收数据。
  • 面向连接:具有连接建立阶段。
  • 流量控制:防止发送方淹没接收方的缓冲区。

TCP使用最大报文段长度(MSS) 的概念,并实现了累积确认流水线机制。


了解了TCP的基本特性后,我们深入其报文段结构。与UDP相比,TCP头部更为复杂。

以下是TCP报文段头部的主要字段:

  • 源端口号 & 目的端口号:各16位,与UDP类似。
  • 序列号:32位,用于对字节流中的字节进行计数,而非对报文段计数。
  • 确认号:32位,表示期望收到的下一个字节的序号,采用累积确认。
  • 头部长度:4位,指定TCP头部的长度(因为包含可变长的选项字段)。
  • 标志位:包括ACK(确认)、RST(复位)、SYN(同步)、FIN(终止)等,用于连接管理和控制。
  • 接收窗口:16位,用于流量控制,指示接收方可用的缓冲区大小。
  • 校验和:16位,用于差错检测,计算方式与UDP相同。
  • 紧急数据指针:通常不使用。
  • 选项:可变长字段,用于支持扩展功能。

上一节我们介绍了TCP报文段结构,其中序列号和确认号是关键。本节中我们来看看它们如何基于字节流工作。

在TCP中,序列号是字节计数器,标识一个报文段中第一个字节在字节流中的位置。确认号则是累积确认,它指定了接收方期望收到的下一个字节的序号,即最后成功接收的字节序号 + 1

例如,一个报文段携带了从字节序号42开始的10个字节数据,那么其序列号字段值为42。接收方成功接收这10个字节后,会回复一个确认号字段为52(42+10)的ACK报文段。

对于乱序到达的报文段,TCP规范没有强制规定接收方必须缓存还是丢弃,这由操作系统实现者决定。


为了实现可靠传输,TCP需要为数据重传设置超时时间。本节中我们来看看TCP如何动态估计往返时间(RTT)并设置超时值。

超时值应略大于RTT。设置过短会导致不必要的重传;设置过长则会使发送方在等待中浪费过多时间。TCP使用以下算法动态估计RTT和设置超时:

  1. 采样RTT:测量从发送一个报文段到收到其确认的时间。
  2. 计算估计RTT:使用指数加权移动平均来平滑RTT样本,公式为:
    EstimatedRTT = (1 - α) * EstimatedRTT + α * SampleRTT
    其中,α的推荐值为0.125。
  3. 计算RTT偏差:为了增加安全边际,TCP还计算RTT样本与估计值之间的偏差的指数加权移动平均:
    DevRTT = (1 - β) * DevRTT + β * |SampleRTT - EstimatedRTT|
    其中,β的推荐值为0.25。
  4. 设置超时间隔
    TimeoutInterval = EstimatedRTT + 4 * DevRTT

这种方法使得超时值能自适应网络状况的变化。


掌握了TCP的各个组件后,我们现在将它们整合起来,理解TCP发送方和接收方的完整事件驱动逻辑。

发送方事件处理逻辑如下:

  • 从应用层接收数据:创建报文段,使用下一个可用的序列号。
  • 启动定时器:如果定时器未运行,则为最早未确认的报文段启动定时器(本质上是回退N步协议)。
  • 设置超时值:使用前述公式TimeoutInterval = EstimatedRTT + 4 * DevRTT
  • 处理超时:重传导致超时的报文段,并重启定时器。
  • 处理ACK:更新发送窗口。如果仍有未确认的报文段,则重启定时器。

接收方事件处理逻辑如下:

以下是接收方对不同到达报文段的处理规则:

  • 按序到达的期望报文段:采用延迟ACK策略,等待一小段时间(如500ms),看是否有后续报文段到达,以便发送一个累积ACK。如果超时,则发送单个ACK。
  • 按序到达且能填补之前空缺的报文段:立即发送累积ACK。
  • 乱序到达的报文段:立即为最后一个按序接收的字节发送重复ACK

为了更直观地理解TCP的交互,我们通过时序图分析几个典型场景。

场景一:ACK丢失

  1. 发送方发送数据(Seq=92)。
  2. 接收方回复ACK(Ack=100),但该ACK丢失。
  3. 发送方超时,重传相同数据(Seq=92)。
  4. 接收方收到重复数据,丢弃之,但再次回复ACK(Ack=100)。
  5. 发送方收到ACK,取消定时器。

场景二:过早超时

  1. 发送方连续发送两个报文段(Seq=92和Seq=100)。
  2. 第一个报文段的ACK未及时到达,发送方超时并重传第一个报文段(Seq=92)。
  3. 接收方收到重复数据,但此时它可能已收到第二个报文段,因此回复一个累积ACK(Ack=120),确认所有已按序收到的数据。
  4. 发送方收到这个更高的ACK,知道两个报文段都已安全到达,继续发送新数据。

场景三:快速重传(优化机制)

  1. 发送方发送一系列报文段,其中一个(例如Seq=100)丢失。
  2. 后续报文段(Seq=120, Seq=140...)按序到达接收方,但接收方因缺少Seq=100,每次都会回复对字节100的重复ACK。
  3. 当发送方收到三个重复的ACK(即总共四个对同一序列号的ACK)时,它推断该报文段可能丢失,于是不等超时,立即重传丢失的报文段(Seq=100)。这称为快速重传
  4. 接收方收到缺失的报文段后,可以发送一个累积ACK,确认所有已接收的数据。

本节课中我们一起学习了TCP实现可靠数据传输的核心机制。我们了解了TCP的报文段结构、基于字节流的序列号和确认号、动态RTT估计与超时设置,以及发送方和接收方的事件处理逻辑,包括快速重传这一重要优化。

然而,TCP的功能不止于此。在下一视频中,我们将探讨TCP如何实现流量控制连接管理,并随后深入拥塞控制这一重要主题。

3.6:拥塞控制原理 🚦

在本节中,我们将从宏观视角审视拥塞控制,旨在从原理上理解拥塞的成因和代价,并识别处理拥塞的两种基本方法。下一节我们将具体探讨TCP如何实现这些原理,但现在,我们先退一步,把握整体概念。

概述

本节我们将学习什么是网络拥塞,分析其产生的根本原因和带来的性能代价,并介绍两种主要的拥塞控制方法。


什么是拥塞?

首先,让我们回答最基本的问题:什么是拥塞?非正式地说,拥塞是指网络中的某个链路太多源主机过快的速度发送太多数据包,导致该链路无法处理。

需要记住,每条链路都有其传输速率。当数据包的到达速率超过链路的传输速率时,队列开始形成,延迟会变得越来越大。如果链路的包缓冲区完全填满,新到达的数据包将被丢弃和丢失。

一个重要的区分是:拥塞控制是关于多个发送方聚合发送过快的问题;而我们在上一节学习的流量控制,是关于单个发送方单个接收方之间的速度匹配。

有了这个背景,让我们深入探讨拥塞的成因和代价。


场景一:无限缓冲的理想情况

我们将从一个简单的理想化场景开始分析。我们观察一个会发生拥塞的单一路由器,并首先假设其拥有无限大的缓冲区(这当然是理想化的)。

该路由器的输入和输出链路容量为 R bits/s,有两条数据流:红色流和蓝色流。我们重点关注红色流:在发送端,应用层向传输层传递数据的速率记为 λ_in;在接收端,数据被递交给应用层的实际速率记为 λ_out,我们称之为吞吐量。我们想探究的问题是:当我们同步提高红色流和蓝色流的发送速率时,吞吐量会发生什么变化?

在无限缓冲的情况下,没有数据包会丢失。每个发送的包最终都会被接收。因此,接收端的吞吐量等于发送端的发送速率,如下图所示。请注意,X轴终点是 R/2,因为如果每个发送方的速率超过 R/2,每条流的吞吐量将简单地达到最大值 R/2,这是因为路由器的输入输出链路每秒无法承载超过 R 比特的流量(两条流各 R/2)。

从吞吐量的角度看,这似乎不错。但请记住,我们在第一章学过,当链路的到达速率接近其传输速率时,会产生很大的排队延迟,如下图所示。因此,即使在这个理想化场景中,我们也看到了代价——延迟代价。


场景二:有限缓冲与重传

现在,让我们放弃“无限缓冲”这个不切实际的假设,考虑相同场景但缓冲区大小有限的情况。

从可靠数据传输的学习中我们知道,发送方在面对因缓冲区溢出或损坏导致的丢包时,会进行重传。因此,我们现在需要更仔细地审视发送速率。具体来说,我们需要区分:

  • λ_in:从应用层传递下来的原始数据速率。
  • λ_in‘:传输层发送数据的总速率,包括重传。

到达路由器的数据包速率是 λ_in‘,而不是 λ_in。请务必理解这个区别,它非常重要。并且,λ_out = λ_in,而 λ_in‘ ≥ λ_in,因为它包含了重传。

对于有限缓冲区的情况,我们仍从一个理想化场景开始:假设发送方能神奇地知道传输的数据包是否有空闲缓冲区。此时,没有数据包会丢失。源发送一个包,在路由器缓冲,最终被传输并在接收端接收。这种情况下,吞吐量 λ_out 等于 λ_in。除了当 λ_in 接近 R/2 时产生的排队延迟外,没有问题。

接下来,我们放松“发送方神奇地知道空闲缓冲区”这个假设,考虑当数据包到达路由器但没有空闲缓冲区时会发生什么。如下图所示,一个数据包到达时发现缓冲区已满,它被丢弃,因此发送方最终重传该数据包的一个副本,这次它找到了空闲缓冲区,通过缓冲区并最终被路由器传输到目的地。

在这种情况下,由于已知丢包而发生重传,总到达速率与吞吐量的关系图大致如下:

  • 在低到达速率区域,缓冲区几乎总是可用的,每个原始传输的数据包都能通过。因此,在这个区域,包含重传(实际上很少发生)的总到达速率 λ_in‘ 基本等于接收端吞吐量 λ_out。总到达速率每增加一个单位,吞吐量也增加一个单位,即图中红色曲线的斜率接近1。
  • 更有趣的是高到达速率区域。到达的数据包中越来越多地包含重传包。因此,接收端吞吐量不再随总到达速率的增加而等比例增加。我们看到,当X轴上的总到达速率 λ_in‘ 接近 R/2(无法更高)时,接收端的最大吞吐量实际上小于 R/2。这个差距很重要,因为一个数据包的N次重传副本最多会占用单包传输容量的N倍资源,但这N次传输最终只贡献一个数据包给吞吐量

现在,让我们看看如果放弃“所有重传都是必要的”这个不切实际的假设会怎样。也就是说,假设发送方可能过早超时(如下图所示),从而实际上向接收方交付了两个数据包副本。在这个例子中,第一个包被延迟,发送方最终超时并重传,两个包最终都到达接收方。当然,接收方只向应用层交付一个段的数据,尽管收到了两个重复段。

有了这些不必要的重传,意味着流中总的重传段更多(有些是必要的,有些是重复的),因此最大吞吐量会进一步下降,从下图中的这里降到那里。

我们可以总结从第二个场景中学到的东西:拥塞导致的丢包需要重传,而N次重传的数据包最多会占用单包N倍的资源(缓冲区和传输容量),但这些N个包最终只贡献一个包给吞吐量。因此,端到端的最大吞吐量可能显著低于拥塞路由器的实际传输容量。


场景三:多跳路径与资源浪费

在我们的第三个场景中,我们考虑四个发送方和四个接收方,发送-接收对之间隔着两个路由器。红色流现在跨越两跳。同样存在重传,因此我们需要像之前一样区分 λ_inλ_in‘,并关注红色流的 λ_in 和吞吐量 λ_out

现在,红色流在这里与蓝色流共享一个链路,在这里与绿色流共享另一个链路。这一点很关键:一个红色流数据包要成功从主机A传输到主机C,必须被两个路由器都成功转发。这很重要,因为如果一个红色数据包通过了第一个路由器,但在第二个路由器丢失,红色发送方将不得不再次重传它,并再次穿越第一个路由器。

另一种看待这个例子的方式是:在第二跳丢失的数据包的第一次传输,本质上浪费了成功通过第一跳所消耗的链路缓冲和传输容量

考虑到这一点,我们想问的问题是:当所有流的 λ_in‘ 增加时会发生什么?

一种可视化和思考这个问题的方式是:随着 λ_in‘ 增加,路径上第一跳路由器的到达速率会增加,从而增加丢包率。现在从渐近角度思考:如果第一跳发送方(例如这里的红色发送方)的发送速率远高于 R/2,这第一跳的流量将挤占所有第二跳的流量,并且这种对第二跳流量的丢弃会发生在所有路由器上。这意味着,当我们调高发送速率时,所有流的端到端(两跳)吞吐量将趋于零。零吞吐量!情况不能再糟了。

因此,我们学到的另一个教训是:在多跳场景中,用于将一个数据包传送到最终丢弃它的路由器所消耗的所有上游网络资源(缓冲区、带宽)都将被浪费。既然这个包无论如何都无法到达目的地,它将不得不被重传,并再次尝试使用端到端路径上的所有资源。


拥塞的代价总结

让我们总结从这三个场景中学到的内容:

  1. 从吞吐量角度看:最好的情况是吞吐量等于从发送方应用层传递下来的流量速率。一旦链路达到其容量,发送更多流量无法使吞吐量超过链路容量。
  2. 延迟代价:当链路利用率接近1时(即流量到达速率接近链路容量),延迟会变得非常大。
  3. 重传开销:当发生丢包时,重传的段(无论是否必要)会降低最大端到端吞吐量,因为链路同时承载原始流量和重传流量。记住,N次重传的数据包最多会占用单包N倍的传输容量和缓冲,但最终只贡献一个包给吞吐量。
  4. 多跳资源浪费:在多跳情况下,用于那些最终在下游丢失的数据包的上游资源(缓冲区、带宽)是真正的资源浪费。在过度拥塞的场景下,这可能导致端到端吞吐量实际上降为零,这种现象被称为拥塞崩溃

应对拥塞的两种基本方法

我们已经看到拥塞绝对是件坏事,这就是我们首先需要拥塞控制的原因——以避免我们刚刚看到的那些代价。下一节我们将看看TCP实际上如何进行拥塞控制。但既然我们在这里探讨大原则,让我们退一步,识别两种基本的拥塞控制方法。我们将看到,TCP同时实现了这两种方法。

拥塞控制的基本方法很简单:当发送方检测到拥塞时,它应该降低其发送速率(即我们之前例子中的 λ_in‘)。

第一种方法:端到端拥塞控制
在这种方法中,发送方通过丢包指示(可能是超时或三个重复ACK)或测量的RTT来推断拥塞。在这种情况下,网络层不提供任何明确的拥塞指示,它只是丢弃或延迟数据包,发送方从这些事件中隐式地推断出拥塞。这是TCP/IP协议栈最初采用的拥塞控制方法,至今仍是TCP拥塞控制算法的核心部分。

第二种方法:网络辅助的拥塞控制
在这种方法中,网络层向传输层提供明确的反馈来指示拥塞,这可以在实际发生丢包或过度延迟之前发生。这种反馈可以通过几种不同的方式提供。一些较新版本的TCP将网络辅助的拥塞控制与TCP原有的端到端拥塞控制结合实现,这实际上是必需的。


总结

本节课中,我们一起学习了网络拥塞的原理。我们探讨了拥塞的成因及其带来的多种代价,包括吞吐量下降、延迟增加、重传导致资源浪费,以及在多跳场景下可能发生的拥塞崩溃。我们还识别了应对拥塞的两种基本方法:端到端(隐式)控制和网络辅助(显式)控制。掌握了这些核心见解,我们现在已经准备好深入探讨TCP具体如何执行拥塞控制,这将是下一节的内容。

3.7:TCP拥塞控制 🚦

在本节中,我们将学习TCP拥塞控制。我们将看到,TCP为了实现拥塞控制,运用了许多我们在上一节中学习到的深刻见解和基本机制。

我们将从被称为“经典TCP”的机制开始,其中TCP发送方会逐渐提高发送速率,直到发生丢包,然后降低速率。我们还将研究一种基于延迟的拥塞控制方法,它通过测量往返时间(RTT)来工作。此外,我们会探讨一种名为“显式拥塞通知”的网络辅助拥塞控制方法,其中IP路由器在拥塞控制中扮演主动角色。最后,我们将以讨论TCP的公平性来结束本节。

经典TCP拥塞控制:AIMD算法 🔄

上一节我们讨论了拥塞崩溃,这是一种非直观的现象:当TCP发送方提高其总速率时,端到端的总吞吐量反而会下降。在20世纪80年代,TCP还没有拥塞控制机制时,网络中确实开始观察到这种现象。1988年,网络研究员Van Jacobson发表了一篇关于拥塞避免与控制的奠基性论文,为我们即将学习的拥塞控制方法奠定了基础。

TCP采用端到端的拥塞控制方法,通过丢包事件来检测拥塞,而不是由拥塞的路由器发出信号。其背后的算法思想非常简单:当网络路径不拥塞(即没有丢包)时,TCP发送方可以提高其发送速率;当发生丢包时,它必须降低发送速率。这种“增-减”机制导致了发送速率呈现出一种“锯齿状”的行为模式。

TCP使用的具体“增-减”算法被称为加性增、乘性减,简称AIMD。在增加阶段,发送方每个RTT将其速率增加一个报文段;当发生丢包时,它将发送速率减半。这个算法非常简洁。

我们可以这样理解:TCP发送方试图找到在不引起丢包的情况下最快的发送速率。它不断试探增加,直到发生丢包,然后减半,接着再次开始增加。这就像孩子试探父母的底线一样。

这里有一个关于何时减半窗口的细节需要注意:只有当TCP通过三重重复确认检测到丢包时,才会将窗口减半。如果发生超时,TCP会将窗口大小直接重置为一个报文段。

你可能会问,为什么是加性增加,而不是乘性增加?这主要与稳定性有关。事实上,在TCP拥塞控制算法提出后,已被正式证明,该算法作为一种分布式异步优化算法,能基于各自接收到的丢包反馈信号来设置各自的发送速率,并具有良好的稳定性。

TCP拥塞控制的实现 🛠️

上一节我们介绍了AIMD的基本思想,本节我们来看看TCP如何具体实现它。

回想我们之前讨论TCP的“回退N步”和“选择重传”时提到的发送方窗口。发送方窗口包含已确认的报文段(绿色)、已发送但未确认的报文段(黄色),以及可以发送的报文段序列号(蓝色)。这些蓝色和黄色的序列号位于所谓的TCP拥塞窗口中。

TCP通过调节拥塞窗口的大小来设置其传输速率,而调节拥塞窗口的方式正是我们刚刚讨论的AIMD算法。

拥塞窗口大小与发送速率有直接关系。如果往返时间为RTT,并且有CWND字节的数据在传输中,那么TCP的发送速率大约是 CWND / RTT 字节/秒。

慢启动与拥塞避免的切换 🚀

到目前为止,我们讨论的是已建立的TCP连接的AIMD行为。我们还需要了解TCP连接如何从初始速率开始提升吞吐量。TCP从初始速率(1个MSS/RTT)开始提升的算法被称为慢启动。这个初始阶段实际上是乘性增加,每个RTT将发送速率翻倍。所以,不要被“慢”字误导,指数增长其实并不慢。

我们已经学习了AIMD和慢启动,现在来看看TCP如何将这两部分结合起来。

TCP从慢启动阶段切换到更谨慎的加性增加阶段,发生在CWND的值达到上次因丢包而减半前的值的一半时。这个切换点由一个名为慢启动阈值的变量跟踪。当检测到丢包事件时,SSThresh被重置为当时拥塞窗口大小的一半。

TCP的AIMD算法已经存在了30多年,期间提出了许多修改方案。其中,一个得到广泛部署的修改是TCP CUBIC。接下来,我们将看看它与经典AIMD有何不同。

TCP CUBIC:更智能的探测 📈

TCP CUBIC的操作方式与AIMD类似,主要区别在于它如何增加其拥塞窗口大小。

理解TCP CUBIC的关键在于回想我们之前关于“探测可用带宽”的概念。假设W_max是发送方上次经历拥塞丢包时的发送速率。问题是,TCP发送方应该如何再次开始探测(即增加发送速率)?

经典的AIMD算法是线性增加。而CUBIC认为,自从上次丢包以来,链路的拥塞状态可能没有太大变化,因此可以更快地增加到接近上次丢包时的速率,但一旦接近那个速率,就要非常小心地增加。

具体来说,TCP CUBIC首先选择一个未来的时间点,希望在那个时间点将其窗口大小增加到上次丢包事件时的窗口大小W_max。然后,TCP CUBIC根据当前时间与达到W_max的目标时间之差的立方函数来增加窗口大小。这意味着,当远离W_max时,TCP CUBIC比AIMD增加得更快;但当接近W_max时,增加得更慢。

由于CUBIC的性能通常被认为优于AIMD,它现在是Linux TCP实现中的默认拥塞避免算法。一项近期的测量研究表明,在最受欢迎的5000个Web服务器中,近50%运行着某种版本的TCP CUBIC。

其他拥塞控制方法:延迟与网络辅助 🧭

我们已经看到,包括CUBIC在内的经典TCP拥塞控制算法采用了基于丢包的端到端方法。实际上,还有两种采用不同方法且部署相当广泛的TCP变体:第一种采用基于延迟的方法,第二种采用网络辅助方法,其中TCP发送方会从TCP接收方和拥塞的IP路由器那里获得显式反馈。

让我们退一步,再看一下全局情况。AIMD和CUBIC会增加TCP的发送速率,直到发生丢包。丢包通常发生在源到目的地路径上某个拥塞的路由器处,我们称这个拥塞链路为瓶颈链路

当瓶颈链路已经几乎总是处于繁忙状态时,让发送方提高发送速率实际上没有好处。路由器在拥塞的输出链路上每秒只能交付R比特。因此,我们希望保持路由器繁忙,但又不让TCP发送方发送得过快以至于溢出路由器缓冲区。换句话说,我们希望保持端到端的管道刚好充满,但不要过满,尤其不要满到引起拥塞丢包。

这就是基于延迟的拥塞控制方法背后的见解。它的工作原理基于使用RTT测量。假设发送方当前测量的RTT值为RTT_measured。发送方还知道在上一个RTT期间发送了多少字节数据,因此可以计算出其测量吞吐量:吞吐量 = 发送字节数 / RTT_measured

发送方还知道RTT_min,即它测量到的所有RTT延迟中的最小值。我们将此值视为无拥塞时的RTT值。在无拥塞状态下,当有CWND字节在传输中时,发送方应看到的吞吐量是 CWND / RTT_min

基于延迟的拥塞控制思想在概念上很简单:如果测量到的吞吐量(CWND / RTT_measured)接近无拥塞吞吐量,那么路径不拥塞,发送方可以发送更多(即增加CWND)。反之,如果测量吞吐量低于理想情况,意味着存在更大的测量RTT和路由器延迟,路径拥塞,因此TCP发送方应该退避(即减少CWND)。

已经有一些基于延迟的协议被提出和部署,它们在如何增减窗口大小上略有不同,但都基于我们这里描述的基本原理。一个较新的版本是BBR,它被Google用于其数据中心互连的内部网络TCP流量,并取代了CUBIC。

显式拥塞通知是一种网络辅助的拥塞控制形式,涉及TCP发送方、接收方以及网络路由器。这种方法旨在避免拥塞,而无需将路由器驱动到过载(即丢包)的场景。

在ECN中,拥塞的网络路由器会在IP数据报头中设置一个比特位,以指示路由器拥塞。TCP接收方然后通过在其发送给TCP发送方的确认报文段头部设置一个ECE比特位,来通知发送方这个拥塞指示。TCP发送方则通过调整其拥塞窗口来应对此拥塞,就像它应对丢包段时使用快速重传一样。

TCP的公平性 ⚖️

让我们通过考虑公平性问题来结束对拥塞控制的学习。首先,什么是公平性?

一个合理的定义是:如果K个TCP会话共享同一个传输速率为R的瓶颈链路,那么每个TCP流应该获得平均R/K比特/秒的吞吐量。你认为我们目前学到的TCP会导致瓶颈链路的公平共享吗?让我们看看。

对于两个流共享瓶颈链路的情况,有一个很好的图形化方法来审视公平性问题。假设连接从一个不公平的点开始,连接1获得的吞吐量多于连接2。问题是,TCP的AIMD算法是否会将实现的吞吐量驱动到公平线上?

由于在起始点,两个连接的总吞吐量小于R,不会发生丢包,两个连接都会因AIMD算法而每个RTT将其窗口增加1个MSS。因此,两个连接的吞吐量沿着45度线移动。最终,两个连接的总吞吐量将大于R,从而发生丢包。假设两个流都检测到丢包,并将窗口减半。然后,它们再次沿着45度线增加吞吐量,如此循环。最终,两个连接的吞吐量将沿着公平共享线波动。无论它们从二维空间中的哪个点开始,最终都会收敛到这种行为,这非常神奇。

让我们从更宏观的视角来结束关于公平性的讨论。请记住,TCP将可靠性、流量控制和拥塞控制捆绑在一起。如果有人想在UDP之上构建一个具有可靠性和流量控制的应用程序,他们当然可以这样做。当TCP连接经历丢包时,它们会降低发送速率,而基于UDP的应用程序(有可靠性但无拥塞控制)则不必降低其发送速率,因此会继续以更高的速率发送,获得更好的性能,并可能饿死TCP连接。

有趣的是,并没有“互联网警察”来强制要求在拥塞链路上公平共享带宽。然而,我们并没有看到任何广泛的“作弊”行为。也许这是因为需要可靠性的应用程序设计者直接基于TCP构建他们的应用程序。

总结 📚

在本节中,我们涵盖了TCP拥塞控制。我们首先研究了经典的TCP拥塞控制,它使用丢包来指示并避免拥塞。我们还研究了使用RTT测量的基于延迟的方法,以及名为显式拥塞通知的网络辅助方法。最后,我们探讨了TCP发送方之间的公平性问题。

我认为,很难高估TCP对互联网成功的重要性。你已经看到互联网协议有很多,但当我们谈论互联网协议栈时,有时我们直接称之为TCP/IP协议栈。我认为这反映了TCP在互联网成功中所扮演的核心角色,特别是TCP拥塞控制算法的重要性。

3.8:传输层功能的演进 🚀

在本节中,我们将探讨传输层协议的未来演进方向,特别是TCP和UDP协议在长期实践中的表现,以及新兴的QUIC协议如何将部分传输层功能上移至应用层,以解决传统协议的一些局限性。


概述

传输层的核心技术主题已经介绍完毕。现在,让我们展望未来,探讨传输层功能可能的演进方向。TCP和UDP协议已存在超过40年,其简洁而强大的服务集支撑了从早期电子邮件到现代流媒体、游戏等各类应用。然而,它们也存在一些固有局限,例如对实时服务和安全性支持不足。近年来,以QUIC为代表的新协议正尝试在应用层重构部分传输层功能,以更好地适应现代网络需求。


TCP与UDP的持久性

上一节我们详细探讨了TCP和UDP的核心机制。本节中我们来看看它们为何能经久不衰。

TCP和UDP协议已稳定运行40余年,期间TCP仅进行了少量修改。长达40年的实践证明了它们提供的服务集虽然简单,但足以支撑从早期互联网应用(如电子邮件、FTP、Telnet)到标准化时尚未出现的应用(如万维网、流媒体、IP语音、游戏等)的惊人范围。

过去20年间,针对特定场景开发了多种TCP变体,其中一些已在实践中部署。如下表所示,这些变体有时适用于相当专业的环境。但总体而言,我们之前在本节中学习的TCP版本仍然是主流的部署方案。

TCP变体 适用场景
TCP Reno 通用互联网
TCP Cubic 高带宽长距离网络
TCP BBR 减少缓冲区膨胀

传输层未提供的服务

回顾我们初次介绍传输层时的讨论,你或许记得传输层未提供某些关键服务。

特别是对实时服务安全性的支持,这些方面至关重要。然而,这些功能主要被添加在了应用层。其形式包括应用层协议、分布式应用层基础设施(如内容分发网络和数据中心),以及靠近客户边缘网络的应用层服务提供商。

我们在第2章学到,HTTP自诞生以来几乎一直运行在TCP之上。然而,情况正在发生变化。新版本的HTTP,即HTTP/3,正在应用层构建大量传输层功能,并转而运行在UDP之上。让我们通过了解QUIC来结束这部分内容。


QUIC:基于UDP的快速互联网连接

以下是QUIC协议的核心介绍。

QUIC(Quick UDP Internet Connections)是一个旨在位于HTTP之下并运行在UDP之上的应用层协议,其结构如下图所示。

[应用层 (如 HTTP/3)]
        |
        v
[传输层 - QUIC (基于UDP)]
        |
        v
[网络层 - IP]

它已在许多Google服务器、Chrome浏览器和移动版YouTube应用中广泛部署,并且正在IETF(互联网工程任务组)进行标准化。

从技术角度看,我们无需学习太多新内容,因为QUIC采用了我们已在TCP中学到的可靠性、拥塞控制和连接管理方法。事实上,如果你查看QUIC的草案规范,其中写道:“熟悉TCP的丢包检测和拥塞控制吗?嘿,那就是我们!这里采用的算法与众所周知的TCP算法类似。”

既然我们已经仔细学习了TCP的可靠数据传输、拥塞控制和流量控制协议,我们对QUIC会感到非常熟悉。因此,我们无需对这些具体技术多言,但应该简要说明QUIC的连接建立方式以及它如何在一个连接上复用多个应用流。

与TCP类似,QUIC是两端点之间面向连接的协议。因此,它使用握手协议来建立连接,为可靠性、拥塞控制和安全性设置发送方和接收方状态。

当前HTTP的做法是:客户端首先建立一个TCP连接(我们知道这需要整整一个RTT),然后在TCP连接之上建立第二个连接以实现传输层安全性(这需要另一个RTT)。因此,在数据开始流动之前,总共需要两个RTT。

在应用层并使用UDP,QUIC仅在一个RTT内完成握手,并在此次握手中一次性建立可靠性、拥塞控制和安全性状态,如下图所示。

客户端                     服务器
  |---- Client Hello ----->|
  |                        | (建立可靠性、拥塞控制、安全状态)
  |<---- Server Hello -----|
  |         ...            |
  |---- 开始数据传输 ----->|

流的多路复用与队头阻塞

上一节我们介绍了QUIC的高效握手。本节中我们来看看其另一个关键特性:流的多路复用。

QUIC还引入了多个应用层流复用于单个QUIC连接的概念。以下是如何在HTTP/3的背景下理解流。

你可以将流视为为需要从Web服务器检索的N个对象中的每一个分别建立的通道。在传统的HTTP(如左图所示)中,多个对象是串行地一个接一个从Web服务器检索的。拥有多个流的优势在于,多个Web对象可以并发检索,如右图所示。

传统 HTTP/1.1 (串行)       HTTP/3 over QUIC (并发)
[对象1请求] ------------>   [对象1请求] ------------>
[对象1响应] <------------   [对象2请求] ------------>
[对象2请求] ------------>   [对象3请求] ------------>
[对象2响应] <------------   [对象1响应] <------------
[对象3请求] ------------>   [对象2响应] <------------
[对象3响应] <------------   [对象3响应] <------------

每个独立的流都有自己的可靠性和安全性保障,但它们都受一个公共的拥塞控制协议管理,如下图所示,该协议看起来类似于DCCP(数据报拥塞控制协议)。

[流1: 可靠性 + 安全]
[流2: 可靠性 + 安全]  --> [公共拥塞控制 (如类DCCP算法)]
[流3: 可靠性 + 安全]

在这个动画示例中,第一个对象被成功检索,但第二个对象的检索出现了错误。在原始HTTP协议的情况下,第三个对象的检索必须等待第二个对象被正确请求和恢复。而在QUIC的情况下,第三个对象的检索可以与第二个对象的错误恢复过程并发进行,如右图所示。

当一个工作单元被阻塞时(例如,此处第二个对象的传输),这种阻塞会停滞所有排在它后面的工作,这种现象被称为队头阻塞。QUIC通过独立的流消除了应用层级的队头阻塞。


总结

本节课中我们一起探讨了传输层功能的未来演进。

我们对传输层功能未来发展的展望就此结束。我们现在真正完成了传输层的全部内容。让我们通过总结来收尾,并看看接下来的学习方向。

TCP和UDP作为互联网的基石,其设计经受住了时间的考验。然而,为满足更低延迟、更高安全性和更高效传输的现代需求,演进正在发生。QUIC协议代表了一种重要趋势:将部分传输层功能(如可靠传输、拥塞控制、安全握手)上移至应用层,并基于UDP构建,从而在保持兼容性的同时,实现了更快的连接建立、多流并发以及队头阻塞的消除。这预示着网络协议栈的设计可能变得更加灵活和模块化。

3.9:传输层总结 🎯

在本节课中,我们将对传输层的学习进行总结。我们将回顾传输层的关键原理、核心服务以及两个主要协议(UDP和TCP)的实现。通过本节,你将巩固对传输层在整个网络体系结构中作用的理解。


至此,我们完成了对传输层的研究。我们覆盖了非常广泛的内容,希望你确实学到了很多知识。

我们探讨了传输层的原理。我们研究了多路复用多路分解,考察了传输层提供的服务。我们深入分析了可靠数据传输流量控制以及拥塞控制。此外,我们还具体研究了传输层协议(UDP和TCP)的实例化与实现。我们确实涵盖了大量的知识,衷心希望你收获颇丰并享受这一学习过程。


接下来,我们将要离开网络的“边缘”。在边缘部分,我们研究了应用层和传输层。现在,我们将深入网络核心,去探究所谓的网络数据平面控制平面。相信你会发现这部分内容非常有趣。


本节内容回顾 📝

以下是我们在传输层章节中探讨的核心主题:

  • 传输层原理:包括端到端通信的逻辑基础。
  • 多路复用与多路分解:这是指主机将多个应用进程的数据通过同一个网络接口收发的能力。其核心是通过端口号来区分不同进程。例如,套接字编程中常用 (IP地址:端口号) 来唯一标识一个通信端点。
  • 传输层服务:主要为应用层提供逻辑通信服务,包括可能的可靠交付、吞吐量保证、定时和安全性等。
  • 可靠数据传输:确保数据完整、有序地从发送方传递到接收方。其核心机制通常涉及序号确认重传。一个简化的可靠数据传输协议(rdt)状态机是其经典描述。
  • 流量控制:防止发送方发送数据过快,导致接收方缓冲区溢出。在TCP中,这是通过接收窗口(rwnd) 字段实现的。
  • 拥塞控制:防止发送方发送数据过快,导致网络中间设备(如路由器)过载。TCP的拥塞控制算法包括慢启动拥塞避免快速重传快速恢复等阶段。
  • 协议实现:我们具体分析了两个传输层协议:
    • UDP:一种无连接的、不可靠的简单传输协议。其报文段结构简单,开销小。
    • TCP:一种面向连接的、可靠的传输协议。它提供了流量控制、拥塞控制以及全双工通信。

总结

本节课中,我们一起系统回顾了传输层的核心知识。我们从基本的多路复用原理出发,逐步深入到可靠传输、流量与拥塞控制等复杂机制,并最终落脚于UDP和TCP这两个具体协议的实现。传输层作为连接应用程序与底层网络的关键桥梁,其设计深刻影响着互联网的可靠性与效率。

在接下来的学习中,我们将目光从网络边缘转向网络核心,开始探索数据如何在网络中实际被转发(数据平面),以及路由决策是如何做出的(控制平面)。这将是理解互联网整体运作的又一重要篇章。

4.1:网络层简介 🚀

在本节课中,我们将要学习计算机网络的核心——网络层。我们将从宏观视角了解网络层的角色,并区分其两大核心功能:数据平面与控制平面。最后,我们将探讨互联网网络层的服务模型。


网络层概览

上一节我们介绍了应用层和传输层,它们主要在网络边缘发挥作用。本节中,我们将深入网络核心,探讨网络层本身。

网络层是互联网的“粘合剂”,它运行在数十亿台主机和路由器上,是网络中最有趣也最具挑战性的部分之一。我们将分两部分来学习网络层:数据平面控制平面


网络层的服务视角

为了理解网络层,我们首先从其提供的服务开始。网络层为上层传输层提供服务。

在发送主机(网络边缘),网络层接收来自UDP或TCP的传输层报文段,并将其封装成一个IP数据报。数据报包含网络范围的寻址信息,随后被传递给链路层进行传输。

在接收主机,网络层接收数据报,检查校验和等信息,提取有效载荷,并将报文段多路分解到相应的上层传输协议(UDP或TCP)。

然而,网络层真正有趣的部分在于网络核心。


网络核心:路由器

在网络核心,路由器是主要的网络层设备。它的工作很简单:从输入链路接收来自相邻主机或路由器的数据报,并将其转发到适当的输出链路。

这引出了两个关键问题:

  1. 本地问题:路由器如何为到达的数据报确定“适当”的输出链路?
  2. 全局问题:所有路由器的转发操作如何协调,以确保数据报通过互联网中数亿台路由器,沿着一条良好的端到端路径从源主机传输到目的主机?

学完网络层后,你将掌握回答这些问题的原理与实践。


两大核心功能:转发与路由

本地与全局的区分清晰地体现在网络层的两个关键功能上。

以下是这两个功能的详细说明:

  • 转发:这是路由器本地的动作,负责将数据包从路由器的输入端口移动到其输出端口。这个过程通常在纳秒级时间尺度上发生,并由硬件实现。

    • 类比:可以将其想象为驾车通过一个单一的交叉路口或环岛。
  • 路由:这是网络范围的活动,负责确定数据包从源主机到目的主机所经过的路径。路由发生在更长的时间尺度上(通常是秒级),通常由软件实现。

    • 类比:这相当于规划并执行从出发城市到目的城市的整个旅程,需要经过许多交叉路口。

数据平面与控制平面

由于网络层过于庞大和复杂,我们的学习将分为两大部分。

上一节我们区分了转发和路由。本节中,我们来看看它们在网络层架构中的具体体现:数据平面控制平面

  • 数据平面:关注每个路由器(或IP设备)的本地功能。核心问题是:数据包如何从输入端口被移动到适当的输出端口?
  • 控制平面:涉及网络范围的逻辑,用于确定数据报从源到目的的路径。网络管理和设备配置也属于控制平面的范畴。

控制平面有两种主要的实现方法:

  1. 传统方法(每路由器控制):在每个路由器内部运行一个分布式路由算法。各路由器上的算法相互通信,共同计算出本地的转发表

    • 转发表:路由器通过匹配数据报头部信息与转发表中的条目,来决定将数据报转发到哪个输出链路。
  2. 软件定义网络:一个物理上独立的远程控制器(通常运行在具有高可靠性的远程数据中心)负责计算转发表,并将其分发给其控制下的每个路由器。路由器本身只执行数据平面的转发动作。


网络层服务模型

最后,我们来讨论网络层从发送主机到接收主机传递数据报的服务模型。服务模型定义了网络层服务的属性。

可能的服务属性包括:

  • 保证交付
  • 保证交付且有延迟上限
  • 保证按序交付
  • 为数据流保证最小带宽

那么,互联网的网络层服务模型是什么呢?答案是尽力而为服务

在尽力而为服务模型下:

  • 传输的数据报不保证一定能被交付。
  • 更不保证以有限的端到端延迟或最小带宽交付。

你甚至可能认为“尽力而为”是“根本不提供服务”的委婉说法。然而,正是这种极简的服务模型,取得了巨大的成功。


总结与思考

本节课中,我们一起学习了网络层的基础知识。我们了解了网络层在边缘和核心的角色,区分了其转发(本地)和路由(全局)两大功能,并引入了数据平面控制平面的架构划分。最后,我们探讨了互联网采用的尽力而为服务模型

关于尽力而为服务模型的成功,有几点关键思考:

  1. 简单性极大地促进了互联网的广泛部署和采用。
  2. 网络中充足的带宽供给,使得语音、视频等实时应用在大多数时候能够“足够好”地运行。
  3. 大量应用层分布式基础设施(如Netflix的内容分发网络)的部署,弥补了网络层服务的不足,甚至可以说正是尽力而为模型催生了这种基础设施。
  4. 对于电子邮件和Web等服务,TCP拥塞控制机制能够在面对拥塞时退让,这也发挥了重要作用。

总结而言,选择正确的服务模型是互联网原始设计中最重要的决策之一。接下来,我们将从这种宏观视角,深入到单个路由器内部的工作原理细节中。

4.2:路由器内部探秘(第一部分)🚀

在本节课中,我们将深入学习网络层中的转发功能,即数据包如何从路由器的输入端口移动到正确的输出端口。我们将分两部分进行,第一部分将介绍通用路由器架构,包括输入端口、输出端口以及负责在端口间移动数据的交换结构。

路由器架构概述

上一节我们概述了网络层、数据平面与控制平面,并理解了路由与转发的区别。本节中,我们来看看路由器的内部结构。

下图展示了路由器架构的主要组成部分。让我们从输入和输出端口开始。

输入和输出端口是物理层和链路层实现的地方。链路层和物理层可能是有线以太网、光纤或某种无线技术。当然,网络层的关键部分也在输入和输出端口实现。路由器的端口数量可以从很少(例如家用路由器的半打)到非常多(例如骨干路由器中的数百个接口或端口),每个端口可能以每秒数千兆比特的速率运行。

数据包在路由器的控制下,通过交换结构从输入端口移动到输出端口。这确实是路由器的心脏,是所有数据包必须经过的地方。正如我们将看到的,它实际上是路由器内部的一个网络。

路由器还有一个路由处理器,通常就是一个常规的CPU,它执行控制平面功能,控制交换结构,并在输入端口安装转发表,如上图所示。

在此图中,我们也可以相当清楚地区分属于数据平面的路由器组件(它们以高速运行并在硬件中实现)和控制平面(它在软件中实现并在较慢的时间尺度上运行)。

深入输入端口

现在让我们放大观察输入端口。从左边开始,看看我们在这里看到了什么。

图中绿色部分,我们看到一个线路终端功能。这实际上是物理层。它负责通过物理介质(无论是铜缆、光纤还是无线)接收比特级传输。

然后是图中蓝色的链路层功能,在这里比特被组装成链路层帧(例如我们稍后将学习的以太网帧)。

最后,图中红色部分是输入端口处的网络层功能。这里可能会形成数据包队列,我们稍后会讲到。但目前要记住的是,在输入端口执行的最关键的网络层功能是查找和转发功能,即确定到达的数据包将通过交换结构转发到哪个适当的输出端口。

这种查找和转发是一种匹配加动作的行为。在传统路由器中,数据包头中的目的地址(即目的主机的IP地址)将决定数据包将通过交换结构转发或导向到哪个适当的输出端口。我们稍后会详细看一下。在那之后,我们将看看通用转发,其中适当的输出端口可以由网络层头部、链路层帧头部或传输层段头部中的许多字段决定或确定。例如,在通用转发下,包含发往特定目的地的TCP段的数据包(比如来自特定源主机)可能被导向一个输出端口,而包含来自同一源IP地址的UDP段的数据包可能被导向不同的输出端口,或者可能根本不转发。不过,我们在这里有点超前了。

基于目的地的转发

让我们从基于目的地的转发开始。

以下是一个转发表的简单示例。当我们考虑转发表时,首先要考虑的是,有2^32个(近40亿个)可能的目的地址,我们当然不希望为每个可能的目的地址都设置一个路由表项。因此,转发表项通常被聚合成范围,如下所示,这应该不会让你感到意外。

在这个特定示例中,目的地址在第一个地址范围内的任何数据包都转到输出端口或接口0;目的地址在第二个地址范围内的数据包转到接口1;在第三个地址范围内的转到接口2;否则,默认的出接口将是本例中的接口3。

这一切看起来相当不错且简单。但俗话说,细节决定成败。例如,如果目的地址在第一个范围内的某个子集的数据包应该去接口3而不是接口0,会发生什么?

当然,我们可以将第一个地址范围拆分成多个部分,然后添加这个带有新目的输出端口的新子范围。但事实证明,有一种更简单、更优雅的方法可以做到这一点,这就是所谓的最长前缀匹配

最长前缀匹配

最长前缀匹配相对简单。我们不再像上一张幻灯片中那样使用明确的范围来执行匹配,而是希望使用地址前缀,如下所示。

这里我们有一个包含四个条目的表。第一个前缀是11001000 00010111 0001(21位)。第二个前缀的长度是24位,所以它是一个更长的前缀。第三个前缀也有21位。右边的星号代表通配符或“不关心”的比特,它们不是前缀的一部分,它们代表地址范围中的比特。因此,你可以看到,地址范围和前缀实际上是同一回事,但正如我们将看到的,使用地址前缀比使用地址范围要容易得多。

最长前缀匹配规则的工作原理如下:对于一个32位的IP地址,要匹配一个前缀,该地址的所有最左侧比特(每一个)都必须与前缀中的1和0匹配。在所有匹配的前缀中,我们希望找到最长的那个。

最长前缀匹配有时也称为最具体匹配,因为匹配的最左侧地址比特数量最多。

看看底部的地址,你能根据最长前缀匹配规则找出它们匹配的前缀吗?为什么不暂停一下想一想?

第一个例子只匹配表中第一行的前缀,所以这很简单。第二个地址更有趣。它的前21位匹配第三个表项,但它的前24位匹配第二个表项。因此,最长前缀匹配是第二个表项,带有此地址的数据包将被转发到与第二个表项关联的接口1,而不是接口2。

如果你理解了这些例子,那你肯定掌握了最长前缀匹配规则。

我们稍后会看到,最长前缀匹配与网络寻址结合得非常自然和巧妙。

交换结构

正如前面提到的,这种匹配加动作通常在硬件中执行。匹配通常使用所谓的三态内容可寻址存储器(TCAMs)来完成,其中地址被呈现给TCAM,匹配值在一个时钟周期内返回,与表的大小无关。因此,TCAMs可以实现非常非常快速的查找。

一旦通过最长前缀匹配确定了数据包的适当输出端口,数据包就准备好被转发到交换结构中。让我们看看交换结构内部发生了什么。

交换结构是路由器的核心。它的工作是将数据包从交换结构的输入端传输到输出端,即将数据包从输入端口移动到由最长前缀匹配确定的输出端口。

交换结构最重要的特性之一是它的交换速率,即数据包可以从输入端口移动到输出端口的最大速率。如果有n个输入端口,每个输入速率为R,而交换机的交换速率为n * R,那么在某单位时间内到达的所有数据包都可以在这段时间内被交换到它们的输出端口。在这种情况下,数据包在交换机的输入端不会经历显著的等待。这被称为无阻塞交换机。但高性能的无阻塞交换机比那些可能偶尔会阻塞数据包并迫使它们在输入端等待的交换机更昂贵。因此,并非所有路由器都有无阻塞的交换结构。

如果存在阻塞,数据包将不得不等待轮到它们通过交换结构传输,在交换结构输入端的这些红色方框处,这被称为输入端口排队

构建交换结构的方法

现在,如何构建高速、高效、经济的交换结构本身就是一个研究领域,实际上有整个课程专门讨论这个话题,如果你对此感兴趣,你可能想选一门。因此,我们在这里只非常简要地涉及这个话题。

如下图所示,我们可以大致确定三种交换方法:通过内存交换通过总线交换通过互连网络交换。实际上,最后一种方法可能是实践中采用最广泛的。

早在20世纪70年代和80年代,第一批路由器实际上就是传统的计算机,输入和输出端口之间的交换是在CPU(你可以将其视为路由处理器)的直接控制下完成的。输入和输出端口在传统操作系统中充当传统的I/O设备。带有到达数据包的输入端口会通过中断信号通知CPU。然后,数据包可以从输入端口缓冲区复制到处理器内存中,CPU随后使用目的地址在转发表中查找适当的输出端口(输出设备),然后将该数据包的内容写入输出设备的缓冲区。因此,从许多方面来看,你可以看到网络端口实际上只是另一种类型的I/O设备。

与将数据包从输入端口移动到内存,再从内存移动到输出端口不同,通过总线交换跳过了中间传输到内存的步骤,允许输入端口直接将数据包写入输出端口缓冲区。这意味着数据包只需穿过总线或背板一次,而不是两次。在这种情况下,交换速度受限于总线带宽。

第三种类型的交换结构是互连网络,这确实是最有趣的。路由器的互连结构与用于在多处理器计算系统中连接处理器的互连网络有很多共同之处。有纵横制交换机,通过n²个互连点直接将n个输入连接到n个输出。但更典型的是,当连接n个输入到n个输出时,会使用多级交换网络,通常称为纵横网络。这些多级交换网络通过串联(即在多个线性级中)和在给定级内并联互连较小尺寸的交换元件构成。在此处显示的示例中,一个8x8交换网络由四个4x4和四个2x2的较小交换机构成。当我们学习数据中心网络中主机如何互连时,会再次看到纵横网络。

因为这些交换结构从其输入端到输出端有并行路径,我们希望能够并行利用这些路径。因此,通常使用这些交换结构时,会将单个数据报分割成多个较小的固定长度单元(有时称为信元),并沿着并行路径将这些信元从交换结构的输入端交换到输出端。然后,在数据报的所有部分都到达后,在输出端口从分割成的组件信元中重新组装原始数据报。

并行交换结构

到目前为止,我们一直将交换结构视为一个单一的实体。但正如我们刚刚在互连网络中看到的,可以利用并行性来构建高性能交换机。这个想法可以推广到采用多个交换结构平面并并行使用它们,如下图所示。这里的图表实际上是思科运营商路由系统的示意图,其基本单元有八个并行交换平面,每个内部都有一个三级互连网络。正如你所看到的,通过利用并行性,可以在单个路由器内实现数百太比特的交换容量。

总结

本节课中,我们一起学习了路由器内部结构的第一部分。我们概览了路由器架构,看到了输入端口、交换结构和输出端口,并详细研究了寻址和最长前缀匹配。下一节,我们将深入输出端口,重点探讨数据包缓冲和调度。

4.2:路由器内部探秘(第二部分)

在本节中,我们将深入探讨路由器内部的两个核心机制:分组调度缓存管理。我们将了解它们如何影响网络性能,并学习几种实际应用的调度策略。最后,我们还将触及一个与这些技术紧密相关的社会性话题——网络中立性。


输入端口排队与队头阻塞

上一节我们介绍了路由器的输入端口、输出端口和交换结构。本节中,我们来看看当数据流在这些组件间流动时,可能发生的排队现象。

首先,我们关注输入端口。当交换结构的处理速度低于所有输入链路速率之和时,就会在输入端口发生排队。在单位时间内,到达的报文数量可能超过交换结构从输入端转移到输出端的能力。

一种在交换结构输入端特有的排队现象被称为队头阻塞。当来自不同输入端口的报文都想去往同一个输出端口时,就会发生队头阻塞。如果一次只能将一个报文从输入端转移到给定的输出端,那么想去往同一输出端口的K个报文中,将有K-1个必须在输入端等待。这些等待的报文还会阻塞其所在输入队列中排在后面的报文,这就是队头阻塞。

以下是一个队头阻塞的示例,其中报文的颜色代表其目的输出端口:

  • 假设在时间T,顶部和底部的输入端口各有一个红色报文要去往上方的输出端口。
  • 在一个时钟周期内,顶部的红色报文被从输入端转移到了输出端。
  • 中间队列的蓝色报文也能转移到其目的输出端口。
  • 然而,底部的红色报文被阻塞了,因为顶部的红色报文已经占用了那个红色输出端口。
  • 因此,排在这个底部红色报文后面的绿色报文就经历了队头阻塞。

输出端口:缓存需求与分组丢失

现在,让我们聚焦于输出端口,因为这里是真正的“行动”发生地。我们首先来看看为什么需要缓存。

假设输出端口的链路传输速率为 R 比特/秒,而交换结构是非阻塞的,能够以 n * R 比特/秒的速率向输出端口交付数据。缓存发生的原因就很明显了:数据到达的速率(n * R)可能超过数据离开(发送)的速率(R)。当到达速率超过离开速率时,缓存区就会被填满。

由于缓存区容量是有限的,可能没有足够的空间来存储所有需要缓存的报文,因此一些报文将不得不被丢弃。正是在输出端口这里,发生了拥塞导致的分组丢失

问题的根源并非交换结构交付过快,而在于网络边缘有太多的运输层发送方,向网络中注入了太多的报文,导致它们都试图通过这个拥塞的输出端口。


缓存容量:多少才合适?

面对缓存和拥塞,你可能会想:路由器应该配备多少缓存才合适?拥有大量缓存似乎是好事,因为可以减少因流量突发性导致的丢包。

然而,即使在网络发展50多年后的今天,“多少缓存才是合适的”这个问题在很大程度上仍未完全解决。目前有一些建议:

  • RFC 3439经验法则:缓存容量应等于典型的往返时延(例如几百毫秒)乘以输出链路容量。
  • 更近期的理论研究:假设运输层发送方彼此独立,建议将RFC 3439的缓存量除以 √n,其中n是经过该链路的流数量。这个值要小得多。

虽然大缓存可以减少丢包,但也有缺点:大缓存意味着更大的时延和更长的RTT。对于游戏玩家和交互式视频会议用户,几十毫秒的时延都至关重要。更重要的是,大的RTT时延意味着TCP发送方会更慢地检测到拥塞并做出反应。

理想的缓存策略是:缓存应足以吸收短期流量波动并保持链路繁忙,但又不能太大,以免拥塞控制反应变得迟钝。这就像烹饪中的盐,适量则佳,过量则毁。

输出端口的缓存和排队之所以如此复杂和微妙,是因为全球范围内成千上万个活跃发送方的行为,都在这个单一的输出链路缓冲区汇聚。我们在互联网深处的一个点上,看到了全球互联网规模行为的汇聚。


输出端口模型与分组丢弃策略

接下来,我们将探讨缓存管理和分组调度的机制。将输出端口抽象地看作一个队列会很有帮助,如下图所示。

报文到达队列、等待服务、最终被选中服务(即其比特被链路层通过输出链路发送),然后离开队列。

如果一个到达的报文发现没有空闲的缓存空间,它要么被丢弃(这称为队尾丢弃),要么根据某种优先级机制(例如,丢弃低优先级报文),将一个已排队的报文移除并丢弃,以便为新到达的报文腾出空间。

此外,正如我们在学习网络辅助拥塞控制时所了解的,一个已缓存的报文也可能被标记拥塞指示,以信号告知链路正变得拥塞。在互联网的显式拥塞通知机制中,IP首部服务类型字段中的2个比特用于ECN标记。正是在发生拥塞的输出端口,这些比特会被设置。


分组调度策略

现在,我们来看几种实践中使用的分组调度策略。

1. 先来先服务调度
在这种调度方式下,报文简单地按照它们到达输出端口的顺序进行发送。这与我们日常生活中最常见的排队方式一致。

2. 优先级调度
在这种调度方式下,到达输出链路的报文在进入队列时被分类到不同的优先级类别中,如下图所示,我们有高优先级的红色流量类别和低优先级的绿色流量类别。

优先级排队策略会从具有非空队列(即有报文等待发送)的最高优先级类别中发送一个报文。在同一优先级类别内的报文选择通常采用先来先服务的方式。

那么,如何定义优先级类别呢?这实际上由网络运营商(ISP)决定。ISP可能认为网络管理流量非常重要,设为最高优先级;网络电话流量比电子邮件优先级更高,等等。通过查看运输层端口号,可以确定数据报携带的流量类型,这是确定优先级的一种方式。另一种方式可能是基于源地址甚至目的地址。

3. 轮询调度与加权公平排队
在轮询调度下,报文像优先级调度一样被分类。然而,不同类别之间没有严格的服务优先级,轮询调度器在各类别之间交替服务。例如,调度器会从类别1选一个报文,然后从类别2选一个,接着从类别3选一个,依此类推。如果某个类别没有报文,调度器就转到调度顺序中的下一个类别。

一种在实践中被路由器广泛实现的、更通用的轮询排队形式称为加权公平排队。与优先级和轮询调度类似,到达的报文被分类并排入相应的每类等待区域。WFQ调度器以类似轮询的方式为各类服务(例如先服务类别1,再类别2,再类别3,然后重复)。

WFQ与简单轮询的不同之处在于,每个类别在任何时间间隔内可以获得不同数量的服务。其工作原理如下:

  • 每个报文类别i有一个权重 Wᵢ。假设所有权重之和为1。
  • 在任何存在类别i报文要发送的时间间隔内,类别i保证能获得Wᵢ比例的服务
  • 这意味着如果链路速率为R,那么每个服务类别将获得保证的最小带宽 Wᵢ * R

由此可见,加权公平排队允许在每类基础上提供某种带宽保证。


网络中立性:技术与社会政策的交汇

网络中立性是一个我们的计算机网络技术兴趣与社会、政治、经济考量相交汇的领域。我们已经看到了共享资源的机制,但关于这些资源如何共享的社会、政治和经济考量呢?

网络中立性涉及管理互联网服务提供商如何使用我们刚刚学到的流量控制机制(特别是分组调度)来控制网络流量的法律和政策。它涉及多个方面:

  • 言论自由:例如,ISP是否可以拒绝承载某些类型的流量(如特定新闻或政治观点)?
  • 鼓励创新与竞争:例如,ISP是否必须对所有公司(无论大小)的流量给予平等对待?

不同国家在这些问题上采取了不同的立场。我们以美国为例,因为其情况有据可查且公开。

2015年,美国联邦通信委员会关于“保护与促进开放互联网”的命令定义了与网络中立性相关的三条明确规则:

  1. 无阻塞:ISP不得阻塞合法的内容、应用、服务或无危害的设备(受合理网络管理约束)。例如,曾有ISP阻止客户使用与其自身电话服务竞争的网络电话服务,这将不被允许。
  2. 无节流:ISP不得基于互联网内容、应用、服务或无危害设备的使用,损害或降低合法互联网流量(受合理网络管理约束)。例如,曾有ISP通过内部创建并发送TCP重置报文给对等网络应用的客户端和服务器,干扰其流量,这被视为违规。
  3. 无付费优先:例如,所有视频流服务提供商的流量必须被同等对待。一个流媒体服务提供商不能通过付费使其报文在传输给客户时获得更好的服务。

你可能会问,为什么不允许付费优先?付费获得优先服务似乎已是常态。一个论点是,如果现有的大型服务提供商能够支付高额费用获得更好服务,这将为新的竞争者设置很高的市场进入壁垒。当然,也有反对观点认为,付费优先为ISP创造了额外收入,从竞争角度看是好事,因为这使得ISP市场更具吸引力,会鼓励更多投资。

此外,从监管角度看,ISP属于“电信服务提供商”还是“信息服务提供商”至关重要,因为两者受不同法律约束(前者监管更严),而这个问题在美国尚未最终确定。

需要注意的是,这些2015年的规则已被后续的FCC命令大幅修改。在相关法律完善、诉讼和判例法进一步发展之前,可以说情况仍在不断演变,这在许多国家都是如此。

有趣的是,自互联网近30年前向公众开放以来,我们就已经具备了流量优先级区分的技术能力。尽管互联网有着坚实的技术基础,但三十年后的今天,管理这一创造物的社会、政治和经济政策仍未完全定义或达成共识。


总结

本节课中,我们一起深入学习了路由器内部的核心运作机制。

我们首先探讨了输入端口排队及特有的队头阻塞现象。接着,重点分析了输出端口,理解了缓存的需求、分组丢失的发生原因,以及关于缓存容量“多少才合适”的持续讨论。

然后,我们将输出端口抽象为队列模型,介绍了分组丢弃策略(如队尾丢弃和基于优先级的丢弃)以及拥塞标记

分组调度策略部分,我们学习了三种主要方式:

  1. 先来先服务:按到达顺序发送。
  2. 优先级调度:按ISP定义的类别优先发送高优先级报文。
  3. 加权公平排队:为不同类别分配权重,保证其获得相应比例的带宽。

最后,我们探讨了与这些技术密切相关的网络中立性话题,了解了其核心原则(无阻塞、无节流、无付费优先)以及围绕它的社会、政治和经济争论。

至此,我们完成了对“路由器内部有什么”的全面探讨,涵盖了输入端口、输出端口、交换结构以及本节深入讨论的分组调度与缓存管理。接下来,我们将把目光转向互联网协议——IPv4。

4.3:互联网协议(第一部分)🌐

在本节中,我们将深入探讨互联网的网络层。由于内容较多,我们将分两部分进行。在第一部分,我们将涵盖IPv4协议和寻址。

显然,IP协议极其重要,但寻址也同样重要。实际上,寻址是IPv4的一部分。我曾认为寻址是简单直接甚至有些枯燥的,但我后来了解到,寻址与ISP之间的关系、管理边界、小到路由表查找和硬件的技术问题,大到全球寻址和转发的实现方式都密切相关。因此,寻址实际上非常重要且相当有趣。

在第二部分,我们将介绍网络地址转换(NAT)和IP的新版本——IPv6。我相信你会发现这些内容很有趣。

那么,让我们从互联网网络层的宏观视角开始。

网络层概览

还记得我们之前学习过网络层的控制平面和数据平面,以及转发表。转发表是路由器的本地表,用于确定路由器将传入数据报转发到哪个输出端口。

在网络层简介中,我们也了解到,转发表的内容由分布式路由协议或路由器外部的SDN控制器决定。当我们研究网络层的控制平面时,会涵盖路由算法和SDN控制器。

互联网网络层的一个关键部分当然是IP协议,这个著名的协议。但IP协议到底是什么?通过查看下图,你可以看到IP协议不涉及路由算法或SDN控制器,那些是控制平面的功能。相反,IP协议是关于数据报格式、IP地址的结构和解释方式,以及数据包处理规范(例如如何将大数据包分片成小数据包)。因此,IP只是互联网网络层的一部分,尽管是非常重要的一部分。

ICMP协议(我们将作为网络层控制平面的一部分来介绍)也是网络层的一部分。

既然IP协议是关于数据报格式、寻址和数据包处理规范的,那么让我们通过查看IP数据报格式来开始对IP的研究。

IPv4数据报格式 📦

我们将使用下图来逐步讲解IP数据报的各个字段。我知道这看起来可能有点枯燥,但任何学习网络课程的人确实需要了解这些,就像吃蔬菜一样,对你有益。所以你必须学习它,希望你甚至会喜欢它或觉得它有趣。

首先,是版本号字段。这4位指定了数据报的IP协议版本。这里我们看的是IPv4头部。

因为IPv4数据报可以包含可变数量的选项(我们在数据报头部这里看到),所以头部长度字段指示头部有多少字节。这让主机或路由器知道IP数据报中有效载荷实际开始的位置。

大多数IP数据报不包含选项,因此典型的IP数据报头部从这里到这里,是一个20字节的头部。

数据报长度字段指示IP数据报头部加有效载荷的总字节数。这是必需的,因为有效载荷也可以是可变大小的。由于该字段是16位长,IP数据报的理论最大大小是64KB。但数据报通常不大于1500字节,这允许数据报能很好地放入最大尺寸的以太网链路层帧的有效载荷字段中。

服务类型比特包含在IPv4头部中,以区分不同类型的数据报。这些比特的定义和使用方式随着时间的推移而演变。就我们的目的而言,最重要的服务类型比特是用于显式拥塞通知(ECN)的2个比特。还记得吗,这是我们在传输层详细研究过的主题。路由器设置这两个比特来指示拥塞。其余6个服务类型比特用于区分不同的流量类别,然后可以使用我们上一节刚刚研究的缓冲和调度算法,根据它们的流量类别提供不同的服务。

TTL字段是一个计数器,每次数据报通过路由器时减1。如果TTL计数达到0,数据报必须在路由器处被丢弃。因此,TTL字段用于确保数据包不会永远循环,或者在存在转发环路时不会循环很长时间。

上层协议字段指示此IP数据报中的有效载荷将被传递给哪个传输层协议。例如,值6表示此数据报包含一个将被传递给TCP的TCP段。值17表示有效载荷是一个UDP段。

IP标识字段、标志和分片偏移字段在单个大的IP数据报被分片成多个较小的数据报时使用。这不常发生,实际上这些字段甚至没有出现在IP版本6中,所以我们在这里不再多说。你可以通过查阅我们教科书中的指引来了解更多关于它们的信息。

头部校验和是根据IP头部内容计算的互联网校验和。记得我们之前学习过互联网校验和,并且要注意,由于IP头部的一些字段在数据报每次通过路由器时都会改变(例如TTL字段递减),校验和需要在数据报通过的每个路由器上重新计算,这可能很耗时。也许正因为如此,头部校验和字段在IPv6中也去掉了。

我们已经讨论过32位的源和目的IP地址字段。记得我们刚刚在基于目的地的转发中看到,IP路由器使用数据报的目的IP地址来查找数据报应转发到的适当路由器输出端口。

最后,数据报头部中有许多可选字段,我们在这里跳过它们。当然,还有数据报的有效载荷本身,有效载荷是IP将传递给传输层协议的数据传输层段。

我们思考并讲解了很多字段。正如我们提到的,IPv6比IPv4精简得多,因此我们会在那里发现更少的头部字段。

IP寻址基础 🏷️

让我们从几个基本概念开始讨论IP寻址。

首先要知道的重要一点是,IP地址本身并不标识主机或路由器,而是标识一个接口,即主机或路由器上的链路层接口。路由器几乎总是有多个接口,也就是说有多个传入和传出链路。主机也经常如此。例如,我的笔记本电脑有一个有线以太网接口和一个无线802.11接口,每个都有不同的IP地址。

正如我们所见,32位IP地址以所谓的点分十进制表示法书写,每个十进制数对应地址字段中的一个8位字节。这里,32位二进制地址的点分十进制表示是223.1.1.1。

看这张图,你可能会觉得有点不满足。这些链路层接口,这些黑线,似乎模糊地终结在一个蓝色的云里。这是怎么回事?这些接口实际上是如何连接在一起的,以便一个接口可以与连接到同一蓝色云的另一个接口直接通信?

请记住,我们现在处于网络层,这些接口的连接是通过链路层技术完成的,链路层是我们正在研究的层之下的一层。所以,对你问题的一个回答是:耐心点,我们马上会讲到。但如果你迫不及待想看到完整的图景,这里就是。主机和路由器接口可能通过有线以太网交换机连接,也可能通过802.11无线网络连接。但会有一个链路层、局域网或点对点链路协议(实践中通常是以太网或Wi-Fi)用于连接这些接口。我们确实会在稍后学习这个。所以请保持关注。现在,回到网络层。

如果你仔细观察这个图,特别是图中的IP地址,你会注意到彼此连接的接口具有相似但不完全相同的IP地址。这是因为它们都属于同一个子网。

那么,什么是子网?每个子网是网络的一部分,包含所有无需通过中间的第3层(即网络层)路由器即可相互到达的设备。也就是说,它们通过某种链路层技术直接相互连接。

以下是这与寻址的联系。一个IP地址有两部分:子网部分和主机部分。如果两个接口在同一个子网上,它们的IP地址必须有一个共同的子网部分。当然,它们的主机部分不同。

让我们非常具体地定义子网。要定义一个子网,将每个接口从其主机或路由器上分离出来,就像我们在这里做的那样。这将留下孤立的网络岛屿。所以在这个例子中,我们有三个子网。

现在让我们看看寻址。记住,同一子网上的接口将具有相同的IP地址子网部分。所谓的子网掩码说明了它们的高位有多少位是相同的。我们假设是24位。

在这种情况下,这里的下子网有一个24位地址223.1.3。我们说223.1.3/24。这三个接口的地址都以223.1.3开头。

下一个子网是223.1.1/24。注意这四个接口的地址以223.1.1开头。第三个子网地址是223.1.2/24。

让我们看看这个有三个路由器和七个主机的网络。你能找到子网吗?想一想。

让我们断开接口与其主机/路由器的连接以查看子网。

以下是/24子网地址。

我们一直在使用的这种斜线表示法有一个名字,叫做无类别域间路由(CIDR),由于其历史渊源,实际上发音为“cider”。

地址的子网部分可以是任意数量的比特X,一个CIDR化的地址形式为A.B.C.D/X,其中X是子网地址中的比特数,有时当D为0时可以省略。这里是一个32位IP地址及其CIDR化点分十进制表示法的例子。

如何获取IP地址?❓

让我们通过提出一个你可能一直在想的问题来结束对IPv4和寻址的讨论:首先,一个人实际上是如何获得IP地址的?这实际上是两个问题:主机如何获得与其将要加入的子网相关的子网范围内的地址?以及更大的问题:网络(子网)如何获得将被该子网内设备(接口)使用的地址范围?让我们看看这两个问题。

让我们从第一个问题开始。主机如何为其接口获取IP地址?在过去,系统管理员实际上需要手动将IP地址编辑到该主机上的一个文件中。但自那以后我们已经进步了很多,使用即插即用或有时称为零配置的方法,也就是说,使用主机和服务器之间的协议而不是手动配置来获取IP地址。零配置方法的必要性是显而易见的,全球有数十亿台主机,其中一半以上是移动的,这些主机不断地连接到网络,然后断开连接,再连接,如此反复。

主机在网络上获取IP地址所使用的协议称为DHCP(动态主机配置协议)。为了使用DHCP分配即插即用的IP地址,网络需要有一个DHCP服务器来执行该功能。到达的客户端(即想要IP地址的主机)将使用DHCP协议从DHCP服务器请求并接收IP地址。当主机离开网络时,它将放弃其IP地址,该地址随后可以被另一台主机重用,或者稍后被该主机续订。

我们将研究四个要学习的DHCP消息,还有更多,但这些是关键的消息:发现、提供、请求和确认。让我们看看DHCP是如何工作的。

这是我们之前见过的简单网络场景。在这个网络中,我们看到DHCP服务器在这里。通常,DHCP服务器会与路由器放在一起,并为该路由器连接的所有子网提供服务,但我们在这里将其显示为一个单独的服务器,其IP地址为223.1.2.5。

这是到达的客户端,它想要一个在223.1.2/24子网内的IP地址。现在让我们看看DHCP客户端-服务器消息交换实际上是什么样子的。

第一步,到达的客户端广播一个DHCP消息,该消息将被其正在连接的子网中所有主机和路由器的接口接收。发现消息基本上是说:“嘿,外面有DHCP服务器吗?”这是一种服务发现形式。主机知道它需要DHCP服务,因此它发送广播来发现可以提供DHCP服务的服务器。DHCP运行在UDP之上。客户端使用端口68,服务器将使用端口67。特别是,服务器将在与UDP端口67关联的套接字上监听传入的DHCP消息。

以下是DHCP发现消息中字段的详细信息。包含DHCP发现消息的UDP段的客户端源IP地址是0,因为客户端还没有IP地址。目的IP地址是IP广播地址,即全1,255.255.255.255。UDP目的端口号是67,正如我们刚才提到的。希望子网上某处会有一个DHCP服务器在监听这个服务发现消息。还要注意有一个事务ID字段,这里的值是654,客户端将使用它来匹配对此请求的任何回复。

第二步,任何接收到此广播发现消息的DHCP服务器(可能有多个这样的服务器)都可以用DHCP提供消息回复。这条消息基本上是说:“嘿,我是一个DHCP服务器,这是你可以使用的一个IP地址。”

如果我们查看此提供消息的详细信息,我们看到它来自IP地址为223.1.2.5的DHCP服务器(如前图所示),端口号为67。此提供消息正在广播到子网上的所有接口。DHCP消息包含请求主机可以使用的IP地址,即“你的互联网地址”字段,以及一个使用期限(本例中为3600秒)。注意,这里的事务ID与初始提供消息的事务ID匹配,也就是说这是对该消息的回复。客户端可以从多个DHCP服务器接收提供,例如,如果该子网上有多个路由器,就可能发生这种情况。

我们在这里看到的前两个步骤实际上是可选的。思考第三步的方式是(如果两个可选步骤没有执行,这也可以是第一步):到达的客户端进来说:“嘿,这是我想使用的一个IP地址。”也许这是它在步骤2(如果该步骤已执行)中被告知可以使用的IP地址,或者也许它已经拥有的一个地址(在这种情况下客户端实际上是续订对该地址的使用),或者也许是客户端以前使用过的地址。

你可以看到,此消息也是广播的,它包含主机提议使用的IP地址,并且有一个新的事务ID和使用期限。

最后一条消息是来自DHCP服务器的ACK消息,基本上是说:“好的,你可以在给定的使用期限内使用那个IP地址。”

事实证明,主机需要比仅仅一个IP地址更多的配置参数才能正常工作。特别是,它还需要知道第一跳路由器的IP地址,因为来自客户端的任何传出数据包都需要发送到该第一跳路由器。它可能还需要使用的DNS服务器的地址,以及子网掩码(其IP地址中属于子网的比特数)。所有这些都可以手动配置,但也可以在DHCP消息中可选地指定,通常情况就是这样。

网络如何获取地址块?🌍

那么,我们仍然需要问的另一个真正的大问题是:网络如何获得一个地址范围来分配给其网络中的设备(实际上是设备接口)?在许多情况下,它将从其所属的ISP拥有的IP地址范围内分配到一个地址范围。

在这个例子中,较高级别的ISP有一个/20地址范围。然后,这个ISP可以将其地址空间分成8个,比如说/23地址范围,如图所示,并将这些地址范围中的每一个分配给它八个客户网络中的一个。

现在我们可以开始看到寻址和路由之间真正关键的联系,当我们讲到网络层控制平面时,我们会再次回到这个问题。在这个例子中,父ISP(我们称之为Fly-By-Night ISP)有八个客户ISP,如图所示。Fly-By-Night只需要向全球互联网的其他部分通告一个地址前缀:200.23.16.0/20。这个单一的通告地址前缀足以让互联网的其他部分能够路由到这个ISP地址范围内的2^12个地址。

这是一个称为地址聚合(有时也称为路由聚合或路由汇总)的例子。注意,在这个图中,第二个ISP(我们称之为ISPs-R-Us)说:“嘿,把地址范围199.31.0.0/16内的任何东西发给我。”我们马上会回到这一点。

这一切看起来非常整洁有序,但在生活中,事情通常不那么整洁或完美地分层。特别是,让我们问自己,如果八个客户ISP中的一个(比如说组织1)想要将其ISP从Fly-By-Night更改为ISPs-R-Us,同时保持其网络地址范围200.23.18.0/23,会发生什么?Fly-By-Night继续像以前一样说:“把地址前缀200.23.16.0/20内的任何东西发给我。”但关键点在这里。现在ISPs-R-Us说:“嗯,像以前一样把地址范围199.31.0.0/16内的任何东西发给我,但现在它也说把地址范围200.23.18.0/23内的任何东西也发给我。”注意这里的/23,并且注意200.23.18.0/23包含在Fly-By-Night通告的200.23.16.0/20地址范围内。那么我们该怎么办?这里绝对关键的是,ISPs-R-Us通告了一个更长的23位前缀200.23.18.0/23,一个比Fly-By-Night通告的20位前缀200.23.16.0/20更具体的前缀。

我希望,哦,是的,你的脑海中刚刚亮起了一个灯泡。记得当我们研究转发表时,当我们查看路由器内部时,在查找一个32位IP地址时,匹配的转发表条目是具有最长前缀匹配的那个。这正是为什么地址在组织1地址范围内的数据包将被转发到ISPs-R-Us,因为它通告了更长的前缀。

总结与展望 📚

我们现在已经看到了地址分配、使用最长前缀匹配的转发表查找以及传播前缀的BGP路由协议是如何真正紧密联系在一起的。如果你理解了所有这些,你真的掌握并串联了许多关键概念。如果还不是100%清楚,我们研究控制平面时会再次回到这个问题,但如果你还没有完全掌握,也许现在再多思考一下。

我们已经看到了主机如何从DHCP服务器获取IP地址,也看到了客户ISP如何从其提供商ISP获取地址范围。但我们仍然没有回答最高层次的基本问题:ISP如何获得一个地址块?这个最后问题的答案是,IPv4地址空间由一个称为互联网名称与数字地址分配机构(ICANN)的实体拥有、管理和分配。

ICANN进而将地址分配给五个区域注册机构,然后这些注册机构将其部分地址空间分配给ISP。

ICANN还执行许多其他关键的互联网功能,例如管理根DNS服务器、管理域名和分配协议号。记得当我们研究IPv4数据报格式时,我们说上层协议号6对应TCP,数字17对应UDP,这些数字也由ICANN控制。

让我们通过考虑IPv4的32位地址空间来结束这里。2011年,ICANN中央将其可用的32位地址空间的最后一块分配给了区域注册机构。ICANN已经没有更多的地址空间可以分配,尽管区域注册机构中仍有一些未使用的地址空间。在下一节中,我们将研究网络地址转换(NAT),这是一种允许多个IP设备使用单个IP地址的技术,我们还将研究IP版本6(IPv6),它拥有更大的128位地址空间。IPv6始于20世纪90年代,正是因为IETF预见到了IPv4地址空间的耗尽。

你看到这里引用了文特·瑟夫的话,他和鲍勃·卡恩一起,如果必须只选两个人,我们真的可以将其视为互联网的两位奠基人之一。他们都被问了很多关于后来发展成为今天互联网的实验性ARPANET的早期日子,特别是关于32位IPv4地址空间的问题。

我喜欢文特的这句话:“谁知道我们需要多少地址空间?”记住,当今天的互联网架构在20世纪70年代被定义时,它是一个相对较小的国防部项目。

所以,让我们把最后的话留给文特·瑟夫。2017年我在华盛顿特区工作时,在乔治城大学听他做了一个非常棒的“炉边谈话”类型的演讲,他谈到了很多非常有趣的话题,但其中一个与IP的32位地址空间有关。所以让我们听听文特怎么说:我们实际上是如何最终确定32位地址空间的?他们经过了什么计算?看一看。

“所以现在我们有四种不同的网络:以太网、分组无线电网、分组卫星网和ARPANET,原始的ARPANET。所以我们坐下来试图弄清楚我们将如何做到这一点,大约六个月后,我们设计了今天使用的基本协议,就是TCP,后来我们分离出用于实时通信的互联网协议。那么问题是,你知道,我们预计这会有多大?老实说,我们坐下来讨论,这将被国防部使用,它必须在世界各地工作,因为你永远不知道国防部将不得不在哪里运作。所以我们说,好吧。这会有多大?它必须是全球性的。每个国家会有多少网络?我们说,嗯,我们已经完成了ARPANET,这是一个非常重要的国家级网络,所以我们想,也许每个国家会有两个,这样会有一些竞争。所以我们说,好吧,两个。有多少个国家?那时候没有谷歌可以问。所以我们猜是128,因为那是2的幂,这就是程序员的思维方式。所以2乘以128是256个网络。那是8位的标识符。然后我们说每个网络会有多少台计算机?我们说,记住这是1973年,这些是巨大的空调计算机,你知道,以分时模式为400人服务,所以我们说,1600万怎么样?你知道,什么?所以1600万是24位,所以我们最终得到了一个32位的地址空间,如果你计算一下,是43亿个可能的网络终端,在1973年,我认为这个数字比当时世界上的人口还要多。所以我们想,嗯,这应该足够做这个实验了,对吧?所以我们用了这个。所以,人们说,如果你能重来一次,你知道,你会怎么做?一个答案是,嗯,我想我会选择128位的地址空间,这样我们就不必经历这个痛苦的过渡。另一方面,你能想象在论坛上提出一个论点吗:我需要3.4乘以10的38次方个地址来做这个实验。你现在有多少个网络?三个。网络上有多少台计算机?500?他说,有些东西不太对劲,是吧?所以我没有这么做,因为我无法通过‘脸红测试’,但我希望我能做到。”


本节课总结

在本节课中,我们一起深入学习了互联网网络层协议IPv4的核心内容。我们首先回顾了网络层的整体架构,明确了IP协议在数据平面中的核心地位。接着,我们详细剖析了IPv4数据报的格式,逐一讲解了版本号、头部长度、服务类型、TTL、上层协议、头部校验和以及源/目的IP地址等关键字段的作用。

然后,我们转向了IP寻址这一重要主题。我们明确了IP地址标识的是接口而非设备本身,并引入了子网的概念。通过CIDR表示法,我们理解了IP地址如何划分为网络前缀和主机部分,以及子网掩码的作用。

最后,我们探讨了IP地址的获取机制。从微观层面,我们学习了DHCP协议如何通过“发现-提供-请求-确认”四步交互,为主机动态分配IP地址及其他网络配置参数。从宏观层面,我们了解了ISP如何从区域注册机构获取地址块,并通过地址聚合与最长前缀匹配原则,揭示了全球互联网路由可扩展性的关键机制。我们还简要提及了IPv4地址空间的耗尽问题,为下一节学习NAT和IPv6做好了铺垫。

通过本节课的学习,你应该对IPv4协议的基本原理、数据报结构、寻址方式以及地址分配机制有了系统性的认识。这些是理解互联网如何工作的基石。

4.3:互联网协议(第二部分)🌐

在本节课程中,我们将继续深入学习互联网协议(IP)。上一节我们详细探讨了IPv4寻址及其32位地址空间的局限性。本节中,我们将聚焦于两个在20世纪90年代中后期为解决IPv4地址耗尽问题而发展起来的重要技术:网络地址转换IPv6。我们将会看到,这两项技术除了解决地址空间问题外,还带来了其他重要优势,并且正得到越来越广泛的部署。

网络地址转换(NAT)🔄

网络地址转换,简称NAT,其核心思想相当简单。在一个局域网(如家庭网络、机构网络或网吧)内部,所有设备都使用一个被称为私有IP地址的特殊地址范围内的IP地址。例如,10.0.0.0/8 就是这样一个地址范围。

在这个网络内部,主机之间交换的数据报照常使用这些私有地址,此时不涉及NAT。但是,当需要与这个局域网外部进行通信时,NAT就发挥作用了。具体来说,从该网络内部任何主机(可能有数十、数百甚至数千台设备)发送到外部网络的数据报,都将使用同一个32位的公共IP地址。

例如,尽管内部所有主机的IP地址形式都是 10.0.0.0/24,但当它们的数据报通过路由器进入更广阔的互联网时,其源IP地址都会被替换为同一个地址,例如 138.76.29.7。同时,这些外出数据报的源端口号也会被重新映射。实现和管理这种转换的设备就是这里的路由器,它被称为NAT路由器NAT盒子

以下是NAT使用的三个私有IP地址范围:

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

如果你查看连接到家庭网络、机构网络或蜂窝网络的笔记本电脑、平板电脑的IP地址,你很可能会发现它属于上述范围之一。

NAT具有多项优势:

  • 地址复用:所有位于NAT路由器后的主机发出的数据报都使用同一个公共IP地址,极大地节省了IPv4地址。
  • 内部网络灵活性:可以更改局域网内主机的地址,而无需通知外部世界,因为它们使用的是私有地址。
  • ISP更换便利:更换互联网服务提供商时,无需更改局域网内设备的地址。
  • 安全性增强:局域网内的设备对外部世界来说不是直接可寻址或可见的,提供了一定的安全屏障。

NAT的实现机制 ⚙️

接下来我们看看NAT是如何实现的。NAT路由器需要完成以下三件事:

  1. 处理外出数据报:对于每一个从局域网发往互联网的数据报,NAT路由器需要将其源IP地址和源端口号替换为NAT的公共IP地址和一个新的源端口号。需要注意的是,NAT对本地主机和远程主机都是透明的。远程主机只会看到一个来自某个IP地址和端口号的数据报,并会像往常一样使用该地址和端口号进行回复。

  1. 维护转换表:NAT路由器需要记住每一个转换映射对,即将(本地IP地址,本地端口号)映射到(NAT IP地址,新端口号)。这个映射关系被存储在一个NAT转换表中。

  2. 处理进入数据报:当数据报从外部互联网到达,并且目的地是局域网内的某个主机时,NAT路由器需要根据NAT表中的记录,将数据报的目的IP地址和目的端口号替换为对应的内部主机的IP地址和端口号。

让我们通过一个实例来清晰地理解这个过程。

NAT工作实例
假设局域网地址范围为 10.0.0.0/24,NAT路由器使用的公共地址是 138.76.29.7。NAT转换表初始为空。

  1. 主机 10.0.0.1(源端口3345)发送一个数据报到目的地址 128.119.40.186(端口80,通常为Web服务器)。
  2. 数据报到达NAT路由器。路由器将数据报的源地址从 (10.0.0.1, 3345) 更改为 (138.76.29.7, 5001),并相应地在NAT表中创建一条记录:(10.0.0.1, 3345) <-> (138.76.29.7, 5001)。注意,数据报的目的地址和端口保持不变。
  3. 远程主机回复。回复数据报的目的地址是 138.76.29.7,目的端口是 5001
  4. NAT路由器收到回复后,使用目的IP地址和目的端口号 (138.76.29.7, 5001) 作为索引查询NAT表,得到对应的内部地址 (10.0.0.1, 3345)。然后,路由器将数据报的目的地址和端口重写为这个内部地址,并将数据报转发到家庭网络中。

关于NAT的讨论 💬

在结束对NAT的学习之前,需要指出的是,NAT最初颇具争议。一个网络层设备去修改属于传输层(端主机范畴)的端口号,这在纯粹主义者看来是不合适的。他们认为,如果真要解决IPv4地址耗尽问题,应该直接采用IPv6,毕竟IPv6就是为了这个目的而开发的。

NAT也带来了一些复杂性。例如,如果外部主机想要主动与NAT路由器后的主机建立连接,就会遇到所谓的 NAT穿越 问题。虽然可以通过一些技术手段实现,但这些方法通常比较复杂。

尽管NAT存在这些缺点,但网络运营商们用实际行动做出了选择——NAT已被广泛部署,并且在未来相当长一段时间内都将持续存在。

IPv6 🚀

在了解了NAT之后,我们接下来看看IPv6。正如我们提到的,IPv6的主要动机是提供更大的128位地址空间。但除此之外,IPv6还包含了许多其他重要创新。在我们学习IPv6时,还会遇到一个非常重要的新概念:隧道技术

IPv6的设计动机 🎯

是的,IPv6最主要的需求无疑是更大的地址空间。但还有其他一些动机:

  1. 更快的处理速度:IP报头需要在纳秒级速度下处理。这在1981年IPv4标准化时并非必需,但鉴于链路速率的发展,这已成为一项重要要求。IPv6通过简化IPv4路由器处理中一些更复杂的方面来实现快速转发,例如变长报头、数据报分片与重组以及每跳都需要重新计算校验和等问题。
  2. 对流(Flow)的支持:在早期,互联网更多地被视为一个面向数据报的网络。但近年来,端点之间的(或称为连接)的概念变得越来越重要。人们希望提供基于流的服务,而不仅仅是基于单个数据报的服务。IPv6通过在IP报头中引入流标签字段,将“流”的概念提升为一级对象。

IPv6数据报格式 📄

让我们快速浏览一下IPv6数据报的格式。你会看到我们一直在讨论的128位IPv6源地址和目的地址。还有我们刚刚提到的16位流标签字段。需要理解的是,这个字段是用于标记流的机制,但IPv6并未强制规定如何定义流或如何使用这个字段。这些实际上是留给ISP的策略问题。IPv6提供了处理流的机制,而非策略。

8位流量类别字段类似于IPv4中的服务类型字段,可用于为流内的某些数据报或特定类别的流量赋予优先级。和流标签一样,这个字段也是关于机制而非策略的。

版本号、有效载荷长度、下一个报头(上层协议)字段以及有效载荷本身,都与我们在IPv4中看到的类似。希望所有这些对你来说都相当熟悉。

既然这些都很相似,那么更有趣的问题或许是:哪些IPv4中的字段在IPv6中不存在?具体来说,IPv6报头中没有校验和、分片/重组或选项字段。正如我们之前提到的,这使得报头长度固定,有利于更快地处理。分片和重组需要在端点完成,而选项功能可以通过在路由器上将IPv6数据报的有效载荷传递给上层协议来实现。

IPv4到IPv6的过渡:隧道技术 🚇

让我们通过思考以下问题来结束对IPv6的讨论:如果我们目前有一个IPv4网络,但最终希望过渡到IPv6网络,我们该如何实现这种过渡?我们已经看到IPv4和IPv6是非常不同的协议。

我们是否要设定一个“旗帜日”,让全球所有人同时从IPv4切换到IPv6,关闭所有IPv4设备并开启所有IPv6设备?由于许多你可能想到的原因,这非常困难。

相反,我们更希望IPv4和IPv6能够共存并互操作,随着新设备的引入,路由器和主机逐步迁移到IPv6。因此,我们今天拥有的互联网是:一些路由器是IPv4的,一些是IPv6的,还有一些同时支持IPv4和IPv6。

但如何在保持互联网运行的同时实现这种共存呢?这有点像试图在飞机飞行时更换引擎。幸运的是,这并不那么难。用于允许IPv4和IPv6网络互操作的关键技术被称为隧道技术

隧道技术的关键在于,让一个数据报(例如一个IPv4数据报)将其有效载荷承载为另一个数据报(例如一个IPv6数据报)。这听起来可能有点奇怪——一个数据报里面装着另一个数据报?让我们来看看它是如何工作的。

隧道技术原理
回想一下我们在网络介绍中学到的分层和封装概念。在下图中,我们看到两个IPv6路由器通过以太网物理连接。这两个路由器之间的链路层以太网帧,其有效载荷承载着一个IPv6数据报。这是完全正常的操作,没有什么新东西。

现在,让我们再次看两个IPv6路由器,但假设它们除了知道如何处理IPv6,还知道如何处理IPv4(就像它们知道如何处理以太网一样)。并且,这两个路由器不是直接通过以太网连接,而是通过一个IPv4路由器网络相互连接。

这两个IPv6路由器如何相互转发IP数据报呢?答案当然是利用连接它们的IPv4网络。在这种情况下,它们不是将IPv6数据报放在以太网帧中发送给对方,而是简单地将IPv6数据报放入一个IPv4数据报中,寻址并将这个IPv4数据报发送给对方。这个过程就是隧道

隧道技术实例
在这个例子中,路由器A和F是仅IPv6路由器,路由器C和D是仅IPv4路由器,而路由器B和E同时支持IPv6和IPv4

假设左侧的IPv6路由器A需要发送一个IPv6数据报到IPv6路由器F。让我们一步步看发生了什么。

  1. A的转发表指出,IPv6路由器B是下一跳。因此,这个IPv6数据报被转发到B。注意,这仍然是一个IPv6数据报(源地址是A,目的地址是F,都是IPv6地址,并且包含仅IPv6才有的流标签字段)。从A到B的过程没有新内容。
  2. 现在看路由器B,这里变得有趣了。它从A收到IPv6数据报,看到目的地是F,并且IPv6网络中的下一跳路由器是E。这是关键:IPv6网络中的下一跳是E。B需要思考:我如何将这个IPv6数据报转发给E?记住,B和E是通过一个IPv4网络连接的。好在B和E都支持IPv4和IPv6,并且它们之间有一条IPv4隧道。实际上,在B的转发表中,会有一条记录指明:要到达F,需要通过一个通往E的IPv4隧道接口转发。
  3. 于是,B创建一个IPv4数据报,将该数据报的目的地址设为E的IPv4地址(这是关键),并将原始的IPv6数据报作为有效载荷放入这个IPv4数据报中,然后将该数据报转发进隧道。
  4. 让我们仔细看看这个从B发往C(进入隧道)的IPv4数据报。对于这个IPv4数据报(外层),源地址是路由器B,目的地址是路由器E。当然,在这个IPv4数据报内部,是原始的IPv6数据报(内层),其源地址是A,目的地址是F。
  5. 然后,这个IPv4数据报通过IPv4网络,使用我们熟知的IPv4机制被转发,最终到达E。在IPv4网络看来,这只是一个普通的IPv4数据报,目的地址是E。
  6. 在IPv4目的地E,E说:“好的,我是这个红色IPv4数据报的目的地。”于是它查看内部,发现了一个IPv6数据报。它提取出这个IPv6数据报,查看其IPv6目的地址F,在自己的转发表中查找F,然后将这个IPv6数据报转发到通往F的链路上。

在这个例子中,我们看到IPv4几乎可以被视为一种直接连接两个IPv6路由器的链路层技术。通过IPv4网络的路径可以被抽象地看作一条直接连接两个IPv6路由器的隧道。通过这种方式,利用隧道技术,IPv4和IPv6可以共存,并沿着混合了IPv4和IPv6路由器的路径端到端地转发数据报。关键在于,在两种技术(IPv4和IPv6)的边界上,我们需要有能同时处理两者的路由器,而所有现代路由器都具备这个能力。

我们稍后会看到,隧道技术在蜂窝网络中被广泛用于支持移动性,因此它是一个通用且重要的概念。但请注意,这个概念有时学生初次接触会觉得难以理解,你可能需要多思考一下或再听一遍这部分内容,因为它是一项超越IPv4/IPv6互操作的重要技术。

IPv6的部署现状 📈

我们已经看到IPv6在20世纪90年代末就已标准化。那么25年后的今天,它的部署情况如何呢?谷歌报告称,访问其服务的客户端中,有近30%使用IPv6。在美国,国家标准与技术研究院报告显示,约三分之一的美国政府域名支持IPv6。

这算是一些进展,但25年后的今天,IPv4仍然是绝对主导的技术。你可能会想,为什么会这样?当然,NAT的广泛部署缓解了IPv4地址空间的压力,降低了对IPv6的迫切需求。但有趣的是,对比一下过去25年应用层发生的变化:万维网、社交媒体、媒体流、游戏、远程呈现等的出现,应用层发生了惊人的巨变。这恰恰表明,在应用层进行构建、创新和部署是多么容易,而在网络层构建、创新和部署新的“管道”则需要长得多的时间。

总结 📝

在本节课程中,我们深入探讨了位于互联网网络层核心的互联网协议,涵盖了大量的内容。我们学习了IPv4数据报格式、IPv4寻址、网络地址转换以及IPv6。也许你现在感觉有点信息过载,但希望你已经学到了很多。

接下来,我们将学习通用转发,这将为我们后续学习控制平面时的软件定义网络打下良好的基础。

4.4:通用转发 🚦

在本节中,我们将学习一种超越传统目的地址转发的新方法——通用转发。我们将探讨其核心的“匹配加动作”抽象模型,并了解一个名为OpenFlow的标准化实现。


回顾传统路由器转发

上一节我们介绍了路由器的基本工作原理,本节中我们来看看它的演进形式。

传统路由器的工作方式如下:当一个IP数据报到达路由器时,路由器会检查其首部中的目的IP地址,然后在转发表中查找该地址,以确定数据报应从哪个输出端口转发出去。这种基于目的地址的转发方式已经沿用了几十年。

其核心流程可以用以下伪代码描述:

def destination_based_forwarding(arriving_packet):
    dest_ip = arriving_packet.header.destination_address
    output_port = forwarding_table.lookup(dest_ip)
    forward_packet_to_port(arriving_packet, output_port)

通用转发的概念

通用转发在两个方面对传统转发行为进行了泛化

首先,匹配不再仅限于目的IP地址。它可以基于到达分组的多个首部字段进行,包括链路层帧首部、网络层数据报首部或传输层段首部中的字段。

其次,动作空间也远比单纯的“转发”要广泛得多。

在通用转发中,转发表有时被称为流表。当数据包匹配到某条规则时,路由器可以执行的动作包括:

  • 将数据包转发到指定的输出端口(传统转发)。
  • 阻塞或丢弃数据包(防火墙功能)。
  • 修改数据包,例如重写首部(网络地址转换NAT功能)。
  • 将数据包封装并发送给SDN控制器。

此外,每条流规则还可以关联优先级,并维护匹配数据包数量的计数器。


流表示例

以下是路由器流表的一个示例,包含匹配列和对应的动作列:

匹配规则 动作
目的IP = 10.3.. 转发至 端口1
源IP = 128.119.1.* 丢弃
源IP = 10.1.2.34 封装并发送至控制器

如果多个流规则(即多行)被匹配,则需要某种优先级机制来选择最终执行的具体动作。


OpenFlow标准

到目前为止,我们的讨论是通用的。现在让我们来看一个已被标准化的具体通用转发方法——OpenFlow。我们将以最初的OpenFlow 1.0规范为例。

在OpenFlow 1.0中,可以使用多达12个不同的首部字段进行匹配。

  • 网络层字段:如IP源地址、IP目的地址、上层协议类型、服务类型字段。
  • 传输层字段:如源端口号和目的端口号。例如,可以基于知名端口号来允许或阻止特定服务。
  • 链路层字段:也可以基于链路层信息进行匹配。

匹配成功后,可以执行的动作包括:

  • 转发到特定输出端口,或复制并发送到一组端口。
  • 丢弃数据包。
  • 修改下列任何首部中的字段。
  • 将数据包封装并转发给SDN控制器。

OpenFlow应用实例

我们看到,OpenFlow的匹配加动作规则能实现的功能远不止基于目的地的转发。以下是几个具体例子:

1. 实现传统目的地址转发
这个例子表明,通用转发可以完成传统转发能做的所有事情。

  • 规则:匹配目的IP地址为 51.6.0.8 的数据报。
  • 动作:转发至路由器输出端口6。

2. 实现防火墙(阻止服务)
此规则用于关闭经过该路由器的SSH服务(使用端口22)。

  • 规则:匹配目的TCP端口为 22 的数据报。
  • 动作:丢弃。
  • 效果:任何试图通过此路由器SSH到远程主机的数据报都将被丢弃。

3. 实现防火墙(黑名单主机)
此规则用于阻止特定主机发出的所有流量。

  • 规则:匹配源IP地址为 128.119.1.1 的数据报。
  • 动作:丢弃。

4. 实现链路层交换
此规则执行传统的链路层帧转发。

  • 规则:匹配目的MAC地址为 22:A7:23:11:E1:02 的链路层帧。
  • 动作:转发至输出端口3。

通过这些例子,我们看到“匹配加动作”抽象可以用来实现多种不同设备的功能:

  • 实现网络层基于目的地的转发。
  • 实现链路层交换。
  • 实现防火墙功能。
  • 结合重写首部的能力,还可以实现NAT(网络地址转换)类服务。

从本地动作到网络级行为

以上讨论的动作都是本地动作。现在让我们退一步,从更宏观的网络层面来思考。

如果我们能为网络中所有路由器的流表进行编程和指定,那么我们就能实现任何想要的网络级路由行为。我们可以在SDN控制器中计算转发表,通过控制器中的程序生成这些表,并将其安装到路由器中。在这种情况下,甚至不需要路由协议,因为转发表是在SDN控制器中计算的。这是一个非常强大的理念。

以下是一个指定端到端路由行为的简单示例:
假设我们希望从主机H5和H6发往主机H3和H4的流量,通过交换机S1进行路由(即不直接使用S3和S2之间的直连链路)。

以下是各交换机的流表配置:

  • S3的流表:源IP为 10.3.*.* 且目的IP为 10.2.*.* 的流量,从本地端口3转发出去(指向S1)。
  • S1的流表:源IP为 10.3.*.* 且目的IP为 10.2.*.* 的流量,从本地端口4转发出去(指向S2)。
  • S2的流表:从端口2进入、目的IP为 10.2.0.3 的流量,从本地端口3转发(指向H3);目的IP为 10.2.0.4 的流量,从本地端口4转发(指向H4)。

通过精心设计每个节点的流表项,SDN控制器就能有效地编程实现网络级的路由行为。


总结与展望

本节课中,我们一起学习了通用转发和匹配加动作模型。

我们了解到,匹配可以基于链路层、网络层和传输层首部中的许多字段进行。本地动作包括转发、丢弃、修改首部字段或将匹配的数据包发送给控制器。这些本地动作使得第三层路由第二层交换防火墙以及NAT类功能都能在统一的“匹配加动作”抽象下完成。

更重要的是,这为我们预览了控制平面的概念:SDN控制器可以通过精心编排流表项,有效地编程实现网络级行为(如路由)。

“匹配加动作”之所以能实现如此广泛的功能,是因为它本质上是一种有限形式的可编程性——能够对每个数据包定义处理步骤。这种思想可以追溯到约20年前DARPA的“主动网络”项目。如今,研究人员正积极探索用于指定和执行这种每包处理行为的编程语言,其中最引人注目的是P4编程语言

接下来,我们将探讨中间盒,这将为我们提供一个审视互联网架构大局观问题的机会。

4.5:中间盒与互联网架构 🧩

在本节课中,我们将要学习网络层数据平面的最后一个重要概念——中间盒,并从宏观视角审视互联网的架构及其演变。我们将探讨中间盒的定义、功能,以及它们如何影响互联网“端到端”的核心设计原则。

中间盒的定义与功能

上一节我们介绍了通用转发,本节中我们来看看一个利用该抽象实现更多功能的网络实体:中间盒。

RFC 3234将中间盒定义为:“在源主机和目的主机之间数据路径上,执行除IP路由器标准功能之外的任何功能的中间设备”。

这里需要标记两个关键短语。首先,“IP路由器的标准功能”基本上指我们之前学习过的、基于目的地的IP数据报转发。其次,根据此定义,中间盒位于主机之间的数据路径上。因此,它本质上是发生在网络核心(而非终端主机)的一种网络层数据平面功能。

我们已经看到,通用转发的“匹配+动作”抽象可以用来实现远多于“IP路由器标准功能”的功能。以下是使用通用转发在中间盒中实现的几种常见功能:

  • 网络地址转换与防火墙:我们已了解NAT和防火墙如何在中间盒中通过通用转发实现。
  • 负载均衡器:这种中间盒将例如HTTP请求路由到多个镜像Web服务器副本中的任何一个。负载均衡器有时被称为第7层交换机应用层交换机,因为它作用于应用层头部(例如HTTP头部)来进行路由决策。
  • Web缓存:我们在第2章学习的Web缓存也是一种中间盒,尽管它涉及存储和计算,而不仅仅是转发。
  • 内容分发网络:更广泛地说,我们甚至可以将内容分发网络视为一种在网络层和应用层同时运作的中间盒,为流媒体等内容提供分发服务。

中间盒的演变:从专有硬件到软件定义

中间盒在网络中的普及大约始于十年前。最初,这些中间盒是专有的,采用封闭的硬件和软件。你会像购买专有路由器一样购买一个专有的中间盒。

近年来,出现了一种向白盒硬件发展的趋势。白盒硬件本质上是可编程的专用硬件,例如,可以通过像OpenFlow中流表这样的API由所有者/运营商进行编程。然后,软件在此通用的白盒硬件之上实现特定的中间盒功能。

Mosaic(最早的互联网浏览器之一)的创建者、Netscape的联合创始人马克·安德森曾有名言:“软件正在吞噬世界”。在许多方面,我们可以看到这在网络世界也正在成为现实。我们已经看到了软件在软件定义网络中的重要性。除了SDN,还有一项被称为网络功能虚拟化的运动正在兴起,它融合了虚拟化、控制平面与数据平面分离、由软件定义的白盒硬件等概念,并将其推广到需要网络、计算和存储的更广义的网络服务中。

互联网架构:IP沙漏与端到端原则

我们已经看到,NAT、防火墙和其他中间盒执行的网络层功能远远超出了“IP路由器的标准功能”。因此,一个很自然的问题是:它们真的属于网络层吗?为了回答这个问题,我们从一个被称为IP沙漏的图开始。

通常我们将互联网协议栈画成一个矩形,但这个图强调了互联网协议栈的“细腰”特性。虽然互联网在物理层、链路层、传输层和应用层有许多协议,但网络层只有一个协议,即我们学习的IP协议。IP是数十亿互联网连接设备中每一个都必须实现的唯一协议。

这个细腰隐藏了一个事实:从以太网、WiFi、蜂窝网络到光网络,这些具有完全不同底层链路层技术的网络都是互联网的一部分。IP隐藏了这种异构性。从网络层向上看协议栈,IP提供了一个简单的连通性基础,应用层服务可以在此基础上构建。

然而,这个IP沙漏模型现在大约有40年历史了。人们可能会说,就像人到中年腰围会变粗一样,互联网的“腰”在今天也确实有“变粗”的趋势,正如我们看到的中间盒、防火墙、缓存、负载均衡器和NFV的激增。这些中间盒执行的功能远远超出了简单的基于目的地的IP转发。

那么,你可能会问自己:这些中间盒功能的激增如何融入互联网架构的整体愿景?如果你对此感到疑惑,你首先会问:互联网的架构原则究竟是什么?

RFC 1958正好回答了这个问题。它写道:“互联网社区的许多成员会认为不存在一个架构,只有一种传统,这种传统在前25年没有被书面记录下来……然而,用非常概括的术语来说,社区相信目标是连通性,工具是互联网协议,而智能是端到端的,而非隐藏在网络中。”

这就是互联网的三个基石信念:

  1. 目标是连通性:目标是在主机之间传递IP数据包。
  2. 工具是IP协议:IP协议被称为“窄腰”。
  3. 智能是端到端的:智能位于网络边缘,而非网络本身。

你可能会对最后一点感到疑惑。它究竟是什么意思?最后一点有时被称为端到端原则,在一篇题为《端到端论点和系统设计》的论文中得到了清晰的阐述。

端到端论文探讨了在哪里实现功能(如可靠数据传输和拥塞控制)的问题。这些功能可以在网络内部实现,也可以在网络边缘实现。例如,我们知道互联网的可靠数据传输和拥塞控制机制是在网络边缘的TCP中实现的,但并非必须如此。可靠数据传输、确认和拥塞控制可以在路径上的每一跳路由器中逐跳实现。确实,在某些特殊情况下会这样做。然而,仍然可能存在一些故障场景,需要只能在端主机采取的恢复措施。端到端论文认为,在这种情况下,你希望将该功能实现在边缘。因此,它指出,有些功能“只有借助位于通信系统端点的应用程序的知识和帮助,才能被完全且正确地实现。因此,将该质疑功能作为通信系统本身的特性来提供(即,在网络内部提供)是不可能的。”

架构对比:电话网络 vs. 互联网

当我思考“网络边缘智能”这个概念时,我想起了大约20年前看到的一张图。那张图用一个大脑代表智能,用一块砖头代表简单(可能不那么智能)。该图比较了电话网络和互联网的架构,并提出了一个问题:智能在哪里?复杂性在哪里?功能在哪里实现?那张图大致如下:

20世纪的电话网络拥有“笨”的网络端点。这是因为端点(旋转式电话机,可能只有你的父母或祖父母记得)不是计算机,它们确实是简单的设备。因此,相比之下,电话网络中的可编程交换机相当“智能”。所有的功能,所有的智能,都实现在网络内部。它必须如此,因为端系统除了发送拨号脉冲或拨号音以及音频信号外,做不了更多事情。

当互联网出现时,端点和交换机都是可编程的计算机。那么复杂性放在哪里?我们刚才看到的、阐述了互联网三大架构原则的RFC 1958明确指出:“智能是端到端的,而非隐藏在网络中”。这明确地将智能放在了网络边缘,正如我们在这里看到的。这是可能的,因为边缘设备是“智能的”,它们是可编程的。

这就是我记忆中15或20年前的图景。而自那时起,随着中间盒和SDN的兴起,我们现在看到智能以软件的形式,被部署在网络内部“笨”的白盒硬件之上。所以,我今天可能会在这里加一个“大脑”。并且,随着数据中心和内容分发网络的出现,我们看到更智能、更复杂的应用层基础设施被连接在网络内部的各个节点上。因此,在今天的互联网中,显然存在着规模更大、计算更密集、更复杂的“端点”。

总结与展望

本节课中我们一起学习了网络层数据平面的核心总结。我们涵盖了大量内容:从网络服务模型开始,深入路由器内部查看输入/输出端口、交换结构、排队和缓冲区管理;我们详细学习了互联网协议,包括数据报格式、IP寻址、NAT和IPv6;然后我们探讨了通用转发,最后以对中间盒的讨论和对互联网架构的宏观审视结束。

接下来我们将去向何方?我们仍然停留在网络层,接下来将研究网络层控制平面。希望你能继续关注。

5.1:网络层控制平面简介 🚦

在本章中,我们将从第4章学习的数据平面,转向网络层的控制平面。我们将从关注单个路由器的数据平面功能,转变为关注网络范围的全局问题,例如如何确定从源到目的地的路径(路由),以及网络管理和配置问题。本章内容非常精彩,特别是近年来软件定义网络(SDN)带来了大量创新。

我们的学习方法将一如既往地从原理出发,再结合实践。本章将涵盖路由算法、SDN控制器以及网络管理与配置的核心概念。


概述 📋

在上一章中,我们深入研究了数据平面,了解了路由器如何根据本地转发表将数据包从输入端口转发到输出端口。本节中,我们将开启控制平面的学习之旅。

控制平面的核心任务是路由,即确定数据包从源主机到目的主机所经过的端到端路径。这是一个网络范围的全局功能,与数据平面的本地转发功能形成对比。本章我们将探讨实现路由的两种基本方法:传统的每路由器控制平面和新兴的软件定义网络(SDN)方法。


控制平面的两种实现方法 ⚙️

以下是实现网络层控制功能的两种主要架构。

每路由器控制平面

在这种传统方法中,控制平面功能分布在网络中的每一个路由器上。

  • 架构:每个路由器都运行路由算法(如OSPF、BGP),并与网络中的其他路由器交换路由信息(如链路状态、距离向量)。
  • 特点:路由决策通过路由器之间的分布式协作完成。每个路由器基于收集到的全局或局部信息,独立计算自己的转发表。

软件定义网络(SDN)控制平面

在这种现代方法中,控制平面在逻辑上是集中式的。

  • 架构:一个独立的实体——SDN控制器——负责运行控制逻辑和路由算法。
  • 过程:控制器计算出全网的路由决策后,将相应的流表项(即转发表)下发并安装到各个路由器中。
  • 特点:路由器之间不直接交互来计算路径,它们只负责执行控制器下发的转发规则。控制与转发实现了分离。

需要强调的是,无论是分布式还是集中式,计算最短路径的核心算法(如Dijkstra算法)本质上是相同的。区别在于这些算法在哪里以及如何被执行。


本章内容路线图 🗺️

上一节我们介绍了控制平面的两种实现范式,本节中我们来看看本章具体的学习路线。我们将交替学习原理与实践,具体安排如下:

第一部分:路由原理与算法

我们将首先学习路由算法的基本原理,主要包括两类:

  1. 链路状态算法:一种更集中式的算法,以Dijkstra算法为代表。
  2. 距离向量算法:一种分布式的算法,以Bellman-Ford算法为代表。

第二部分:互联网中的路由实践

接着,我们将看到这些算法在当今互联网中的具体实现:

  1. OSPF协议:这是一个域内路由协议,采用链路状态算法,用于在单个自治网络内部进行路由。
  2. BGP协议:这是一个域间路由协议,采用路径向量算法(基于距离向量思想),用于在不同自治系统(即不同网络)之间进行路由。BGP被称为“互联网的粘合剂”,它将全球互联网的各个网络连接在一起。

第三部分:软件定义网络(SDN)

然后,我们将深入研究SDN:

  1. SDN控制器原理:学习逻辑集中式控制器的核心概念。
  2. SDN实践:研究两个开源SDN控制器平台——OpenDaylightONOS,以及促成SDN发展的关键协议OpenFlow

第四部分:网络管理与配置

最后,我们将探讨网络控制平面的另外两个重要功能:

  • 我们将学习ICMP(互联网控制报文协议)。
  • 我们将了解网络管理协议SNMP和用于网络配置的协议与语言,如NETCONFYANG

总结 🎯

本节课中,我们一起开启了第5章控制平面的学习。我们首先明确了控制平面(负责路由)与数据平面(负责转发)的核心区别。接着,我们介绍了实现控制平面的两种架构:传统的分布式每路由器控制平面和现代的集中式SDN控制平面。最后,我们预览了本章的学习路线图,后续我们将深入路由算法、协议以及SDN等具体内容。控制平面是网络智能的核心,理解它将帮助我们看清整个互联网是如何协同工作的。

5.2:路由算法之链路状态路由 📡

在本节中,我们将介绍两种在实践中广泛使用的路由算法,用于计算从给定源节点到给定目的节点的路径。第一种被称为链路状态算法,第二种被称为距离向量算法。尽管它们共享计算最短路径或最低成本路径的共同目标,但我们将看到,它们在计算这些最短路径的实际方式上存在很大差异。

任何路由算法的目标都是通过路由器网络,在源节点和目的节点之间确定一条的路径或路由。为了理解路由算法,我们需要稍微展开说明一下。我们所说的“路径”是什么意思?通过路由器网络的路径是什么?此外,“好”意味着什么?一条路由“好”或比另一条路由“更好”意味着什么?

路径与“好”的定义 🛤️

让我们将路径定义为数据包从给定的初始源主机到最终目的主机所经过的一系列路由器。例如,从左边的源主机到右下角的目的主机的路径,会经过这五个路由器。路径作为一系列路由器,隐含了连接路径中路由器的链路序列。这些链路很重要,我们马上就会看到。

那么“好”意味着什么呢?它可以有很多不同的含义,可能是最低成本路径,可能是最快路径,也可能是最不拥塞的路径。正如我们将看到的,成本的定义和“好”的定义,将由网络运营商来决定。在深入探讨路由算法之前,我想补充一点,路由绝对是网络领域的十大挑战之一。

图论抽象 📊

我们将使用图论抽象来描述路由算法,这对于任何上过数据结构或算法课程的计算机科学本科生来说都是一个熟悉的概念。一个图由一组节点组成,这些节点可能对应于网络内的路由器。这些节点通过边或链路连接。

每条链路都有一个相关的成本。节点A和B之间的链路成本记为 C(A, B),是连接A和B的直接链路的成本。例如,这里链路W和Z之间的成本 C(W, Z) 是5。X和Y之间链路的成本是1。链路成本在每个方向上可以不同,也可以相同(如本例所示)。最后,两个不直接连接的节点之间的链路成本将是无穷大。例如,不直接连接的U和Z之间的链路成本是无穷大。

那么这些成本从何而来呢?路由算法或协议本身并不真正关心,但在实践中,它是由网络运营商定义的。成本可以是1,在这种情况下,最低成本路径算法就是最短路径算法;或者成本可以与带宽成反比,带宽越高,成本越低;或者成本可以与链路的拥塞水平(即排队延迟)直接相关,拥塞水平越高,成本越高。

路由算法的分类 🗂️

我们马上会看两种路由算法。但总的来说,我们可以根据算法是全局的还是分散的,以及是静态的还是动态的来对任何路由算法进行分类。

全局算法中,算法拥有关于网络拓扑和所有链路成本的完整全网信息。具有全局状态信息的算法有时被称为链路状态算法,因为算法必须知道网络中每条链路的成本。Dijkstra算法就是一个全局链路状态算法的例子。

分布式或分散式路由算法中,最低成本路径的计算是由路由器以迭代、分布式的方式进行的。没有路由器拥有所有网络链路成本的完整信息。相反,每个路由器开始时只知道其直接连接的链路的成本(即其本地邻居信息),然后通过与直接相邻节点进行计算和信息交换的迭代过程,节点迭代地计算到一组目的地的最低成本路径。我们将学习的Bellman-Ford算法就是一个分布式算法的例子,也称为距离向量算法,因为它迭代地计算一个向量,该向量包含当前已知的到所有网络节点的最低成本。

路由算法也可以根据其运行的时间尺度分为静态的动态的(或准静态的)。

Dijkstra链路状态路由算法 🧮

我们现在准备来看看Dijkstra的链路状态路由算法。我知道,如果你是像马萨诸塞大学Compsi 311这样的算法课程的学生,你已经见过Dijkstra算法了。了解到你在理论课上学到的算法实际上正在实践中使用,这不是很棒吗?我几乎可以向你保证,现在作为本视频一部分传输给你的数据包,几乎肯定是使用Dijkstra链路状态路由算法路由给你的。

Dijkstra链路状态路由算法是一种集中式算法,因为它假设进行计算的节点知道完整的网络拓扑和网络中所有的链路成本。算法本身将计算从一个节点(我们称之为源节点)到网络中所有其他节点的最低成本路径。你可以看到这如何为该节点生成一个转发表。Dijkstra算法有一个非常好的特性:它是迭代的。经过K次迭代后,我们将知道到最近的或成本最低的K个目的地的最低成本路径。

以下是我们要使用的符号:

  • C(A, B):节点A和B之间的直接链路成本。如果节点A和B未连接,则此成本为无穷大。这仅仅是两个直接相连节点之间的一跳直接链路成本。
  • D(A):从源节点到目的地A的最低成本路径成本的当前估计值。正如我们将看到的,随着算法的进行,D(A) 将针对所有目的地A进行迭代更新。
  • π(A):从源节点到节点A的路径上的前驱节点
  • N‘:在计算的当前阶段,其最低成本路径已明确已知的节点集合。

现在让我们看看Dijkstra链路状态路由算法的伪代码。简单的部分是初始化。我们要做的是初始化 N‘(记住,N’ 是那些从源节点U出发的最低成本路径已知的节点集合)。我们将初始化 N‘ 只包含源节点U。对于网络中的所有其他节点A:

  • 如果A直接连接到U,那么 D(A) 就等于那一跳的成本(从节点U到A的成本)。
  • 否则,D(A) 将是无穷大。

这就是初始化,很简单。第8到15行是算法的核心,这只是一个循环。在循环的每次迭代中,我们将找到一个节点A,将其添加到 N‘ 中,然后执行一次更新,接着再次迭代。所以这个循环基本上有两个部分:找到一个节点,然后执行更新。现在让我们来看看它。

在第9步和第10步,我们找到一个不在 N‘ 中的节点A(这是一个其最低成本路径尚未明确已知的节点)。我们将找到那个不在 N‘ 中且 D(A) 最小的节点A,然后将其添加到 N‘ 中。记住,一旦节点被添加到 N‘,它就永远在里面了,因为我们绝对知道到达A的最短路径。这就是循环内的识别步骤

然后我们有一个更新步骤,如第11和12步所示。更新步骤如下:我们将更新网络中所有与A相邻(即直接连接)且尚未在 N‘ 中的节点B的 D(B)。更新公式是:D(B) = min( D(B) 的旧值, D(A) + C(A, B) )。新的潜在成本是到达A的最小成本(记住,这个现在已知了)加上从A到B的一跳成本。一旦我们对所有与A相邻的节点B执行了这个更新步骤,我们就循环回去,找到一个新的A,然后从第8步重新开始。我们继续这个循环过程,每次将一个节点A添加到 N‘ 中,直到网络中的所有节点都在 N‘ 中。

理解Dijkstra算法最简单的方法可能是看一个例子。所以我们接下来就做这个。

算法示例演示 📝

在左下角,你看到我们想要运行Dijkstra算法的网络。有六个节点,图中显示了链路及其相关的链路成本。我们要计算所有最低成本路径的源节点是最左边的节点U。

让我们从最简单的初始化步骤开始。记住,初始化步骤说:对于所有节点A,如果A与源节点U相邻,则 D(A) 简单地等于从U到A的一跳直接链路成本。让我们看看这里,节点U的直接邻居是V、W和X。所以你可以看到在第一行,到达V的成本是2,到达W的直接成本是5,到达X的直接成本是1。我们填写了前驱节点,简单地说明节点V、W和X的前驱(从U出发的最短路径)实际上是节点U本身。节点Y和Z被初始化为无穷大,因为它们没有到源节点U的直接一跳连接。

现在该进入我们的第一次循环了(第8、9、10步)。在第9和10步,我们将进行节点识别。我们想找到一个尚未在 N‘ 中的节点A,使得 D(A)(到A的成本)最小,然后我们将把A添加到 N‘ 中。查看上表,我们看到V的成本是2,W的成本是5,X的成本是1。所以X在这里是最小的。我们将把节点X添加到 N‘ 中。你可以在左下角的图上看到,我们画了一个红色箭头,表示从U到X是直接连接。

现在让我们继续到更新步骤(如第11步所示)。我们将更新 D(B) 的方式如下:D(B) 的新值将是 D(B) 的旧值和 (D(A) + C(A, B)) 之间的最小值。这里的逻辑是,我们想更新到B的成本,知道它不可能超过到B的旧成本,但现在我们知道到A的最低成本,并且我们知道从A到B的直接成本,所以我们将这两个相加,这将给出通过A到达B的成本,然后我们将取这两个值中的最小值。你可以看到,在灰色部分,我们更新了 D(V)、D(W) 和 D(Y) 的值。正如你所见,到W的新成本从5降到了4,到Y的新成本从无穷大降到了2。所以我们将在上表中更新这些值,然后迭代回到循环的开头。

现在我们已经完成了表中的两行,又回到了循环的开头。所以我们处于识别步骤。让我们找到一个尚未在 N‘ 中且 D(A) 值最小的节点A。查看上表,我们可以看到节点Y的成本是2,节点V的成本也是2。我们可以任意打破平局,让我们选择Y。所以我们将把Y添加到集合 N‘ 中。

现在我们进入更新步骤(第11步)。鉴于我们已经将Y添加到了 N‘ 中,我们想再次更新所有与Y相邻且尚未在 N‘ 中的节点B的 D(B)。更新公式在这里。让我们看看Y,我们刚刚添加了Y,Y有两个尚未在 N‘ 中的邻居:W和Z。所以我们将更新W和Z的值,如图所示。你可以看到,到W的新成本现在从4降到了3,到Z的新成本从无穷大降到了4。所以我们更新上表,准备再次迭代。

我们第三次进入循环的第8步。再次,我们从识别步骤开始。让我们找到一个尚未在 N‘ 中的节点A,使得 D(A) 最小。当我们扫描在步骤2中计算的行时,我们看到V现在是成本为2的最小值。所以让我们把V添加到集合 N‘ 中。

完成识别步骤后,下一步又是更新步骤。现在我们要更新所有与这个新添加到 N‘ 中的节点V相邻的节点B的 D(B)。更新公式在那里。让我们看看下面我们刚刚添加的节点V。那么,哪些尚未在 N‘ 中且直接连接到V的邻居呢?U已经在里面了,X已经在里面了,但W不在里面。所以我们更新W,如图所示(灰色部分)。我们看到到W的成本没有改变。所以我们完成了更新步骤,让我们再次循环回去。

再次进入循环后,我们首先进行识别:让我们找到一个不在 N‘ 中且 D(A) 最小的节点。嗯,只剩下两个节点不在 N‘ 中:W和Z。W的成本是3,比Z的成本4小。所以我们将把W添加到 N‘ 中。

我们将再次执行更新步骤。你可以看到更新步骤。唯一需要更新成本的节点是Z。所以你看到更新Z成本的步骤,D(Z) 的值没有改变,所以表格保持不变。

我们再次循环回到第8步,进入识别步骤,我们将找到一个不在 N‘ 中且 D(A) 最小的节点A。嗯,只剩下一个节点了,那就是Z。所以我们将把Z添加到 N‘ 中。现在没有节点剩下了,所以没有更新步骤。我们退出算法,全部完成。

现在,如果你看一下左下角的网络,你可以看到从节点U到网络中所有其他节点的最低成本路由树。由此,我们能够恢复转发表。具体来说,从U出发:

  • 如果我们想去目的地V,我们通过这条直接成本为2的链路。
  • 否则,如果我们想去X、Y、W或Z,我们将把数据包转发给X,因为X是从U到所有目的地X、Y、W和Z的最低成本路径上的下一跳节点。

算法复杂度与潜在问题 ⚠️

我希望关于Dijkstra算法的讨论让你对集中式链路状态算法的工作原理有了很好的了解。让我们通过讨论其复杂度(计算复杂度和消息复杂度)以及一个可能的病理情况来结束对Dijkstra算法的讨论。

考虑计算复杂度时,请注意我们需要从第6行到第11行循环N次。每次我们通过该循环时,在最坏情况下需要进行n次比较。所以这将给我们一个 O(N²) 的计算复杂度。

让我们从传播链路状态信息所需消息数量的角度来分析Dijkstra算法的消息复杂度。每个路由器都需要向其他所有路由器广播其链路状态信息。存在一些非常有趣的广播算法,它们只需要 O(N) 次链路穿越就能将广播消息从一个源传播到N个其他节点。考虑到现在有N个源,因此传播链路状态的总体消息复杂度是 O(N²)

在结束对链路状态算法的讨论之前,让我们考虑一个可能出现的非常有趣的病理情况。我们还没有过多讨论链路成本,但现在想象一下链路成本是动态的,反映了链路上的负载量。例如,负载越高,成本越高。ARPANET中一些最早的路由算法就使用了这种短期负载相关的链路成本。

我们来看看下面这个简单网络拓扑的例子,其中链路成本等于链路上承载的负载。请注意,现在链路上的成本在每个方向上是不同的。假设节点B、C和D各自只向节点A路由流量,B和D各发送一个单位的负载给A,C发送一个很小的负载ε给A。假设初始路由如图所示(最左边)。当下一次链路状态算法运行时,节点C根据链路负载(也就是成本)确定,到A的顺时针路径现在的成本是1,而它一直在使用的逆时针路径到A的成本是1+2ε。现在C到A的最低成本路径是顺时针的。类似地,B确定其到A的新最低成本路径也是顺时针的,导致路由如第二个图所示。当链路状态算法再次运行时,节点B、C和D都检测到在逆时针方向有一条成本为0的路径到A,于是都将流量路由到逆时针路径。下一次算法运行时,B、C和D都看到顺时针路由的成本为0,因此又将流量路由到顺时针方向,如此往复。

这只是一个玩具场景,但它反映了动态路由算法可能非常微妙的事实。也许正是因为这些问题,后来的路由算法倾向于避免基于短期拥塞或负载水平来定义成本。

总结 📋

好了,这结束了我们对Dijkstra集中式链路状态路由算法的讨论。但我们还没有完成对路由算法的探讨,因为接下来,我们将要看看一种非常不同的算法:分布式的Bellman-Ford路由算法。

在本节课中,我们一起学习了路由算法的基本概念,特别是深入探讨了Dijkstra链路状态路由算法。我们定义了路径和“好”路由的含义,引入了图论抽象来描述网络,并对路由算法进行了分类。我们详细讲解了Dijkstra算法的原理、符号、伪代码,并通过一个具体示例逐步演示了其迭代计算过程。最后,我们分析了该算法的计算和消息复杂度,并探讨了在动态链路成本下可能出现的路由振荡问题。这为我们理解另一种重要的路由算法——距离向量算法——奠定了基础。

5.2:距离向量路由算法(贝尔曼-福特算法)🚀

在本节课中,我们将要学习第二大类路由算法——距离向量路由算法,其核心是分布式贝尔曼-福特算法。我们将了解其工作原理、计算过程、收敛特性,并与链路状态算法进行比较。

上一节我们介绍了迪杰斯特拉的链路状态路由算法,本节中我们来看看分布式贝尔曼-福特距离向量路由算法。这个算法展示了简单的、本地的、直观的分布式计算如何达成与集中式算法相同的结果——计算最小成本路径。

贝尔曼-福特方程:算法的核心🧮

距离向量算法计算最小成本路径的基础是贝尔曼-福特方程。这个方程虽然看起来有些复杂,但其背后的思想非常直观。

贝尔曼-福特方程表达了这样一个概念:如果我想找到从源节点 X 到目的节点 Y 的最小成本路径,那么这条路径的第一跳必定是 X 的某个邻居节点,假设为 V。因此,总成本就是从 XV 的成本,加上从 VY 的成本。这就是通过邻居 V 到达 Y 的总成本。然后,在所有可能的邻居 V 中,选择总成本最小的那条路径。因为 X 的最小成本路径必然经过其某个邻居 V

用公式表示如下:
D_x(y) = min_v { c(x, v) + D_v(y) }
其中:

  • D_x(y) 是节点 X 到节点 Y 的最小估计成本。
  • c(x, v) 是节点 X 到其直接邻居 V 的链路成本。
  • D_v(y) 是邻居 V 到目的节点 Y 的估计成本(来自 V 的距离向量)。
  • min_v 表示对所有邻居 V 取最小值。

理解贝尔曼-福特方程最好的方式是看一个例子。考虑一个网络,源节点是 U,目的节点是 ZU 有三个邻居:VXW。邻居们知道以下信息:

  • 邻居 V 到达 Z 的成本是 5。
  • 邻居 X 到达 Z 的成本是 3。
  • 邻居 W 到达 Z 的成本是 3。

邻居们将这些信息告知 U。根据贝尔曼-福特方程,UZ 的最小成本是以下三个值中的最小值:

  1. c(U, V) + D_V(Z)
  2. c(U, X) + D_X(Z)
  3. c(U, W) + D_W(Z)

代入数字后,U 会发现通过邻居 X 到达 Z 的成本最低,为 4。

距离向量算法:关键思想与步骤⚙️

贝尔曼-福特方程描述了相邻节点距离向量之间的关系,但我们还需要计算这些距离向量本身。计算方式自然地遵循了这种关系。

以下是距离向量算法的关键思想:

  • 周期性信息交换:每个节点会不时地向其所有直接相连的邻居发送自己的距离向量估计。
  • 基于接收信息更新:当一个节点 X 从某个邻居那里收到一个新的距离向量估计时,它会使用贝尔曼-福特方程更新自己的距离向量。

分布式贝尔曼-福特算法包含三个步骤,网络中的所有节点都执行相同的这三个步骤:

以下是每个节点执行的三个核心步骤:

  1. 等待事件:节点等待,直到发生以下事件之一:
    • 从某个直接相连的邻居那里接收到一个距离向量。
    • 检测到本地链路成本发生变化。
  2. 重新计算距离向量:在接收到上述事件后,节点使用从邻居那里最新收到的距离向量,为网络中的所有目的地运行贝尔曼-福特计算。
  3. 通知变化:如果由于贝尔曼-福特计算导致节点自身的距离向量发生改变,那么它将把自己的新距离向量发送给每一个邻居。

然后,节点回到步骤1,开始新的迭代。这个算法非常简单。与链路状态算法不同,节点不需要知道从源到目的地的完整路径,它只需要知道为了沿着最小成本路径到达给定目的地,应该将数据包转发给哪个邻居。

算法特性与信息扩散🌐

距离向量算法具有一些重要特性:

  • 迭代与异步:每次迭代由本地链路成本变化或收到邻居的距离向量更新消息触发。节点可以异步迭代,以不同的速度运行,算法依然能够收敛。
  • 分布式与自停止:只有当节点的距离向量发生变化时,它才会通知其邻居。邻居们仅在必要时才会通知它们的邻居。如果没有变化发生,则无需采取任何行动。

贝尔曼-福特算法可以看作是在网络中扩散信息。为了理解这种扩散概念,让我们看看网络中其他节点是如何逐步了解节点 C 的状态的:

  • t=0 时,C 没有与任何人通信,其他节点没有关于 C 的信息。
  • t=1 时,通过距离向量交换,Ct=0 时的状态传播到了其邻居 B,并影响了 Bt=1 时的计算。
  • t=2 时,关于 C 的信息传播得更远,到达了节点 EA。此时 E 首次感受到 t=0C 状态的影响。
  • 这个过程继续下去,信息像星光一样传播:Et=2 时看到的关于 C 的成本,反映的是 Ct=0 时的状态,即使 E 是在 t=2 时才收到这个信息。
  • 最终,信息需要经过网络直径(本例中为4个时间步)才能从网络一端传播到另一端。

链路成本变化与“坏消息”问题⚠️

到目前为止,我们只看了初始距离向量的计算。经过若干次迭代后,计算过程会静止(收敛)。当没有节点的距离向量再发生变化时,算法就收敛了,不再有距离向量被交换。

我们的距离向量算法也能处理链路成本变化,步骤完全相同:本地节点检测到链路成本变化,使用新的本地链路成本和旧的邻居距离向量重新计算本地距离向量。如果本地距离向量发生变化,就将其发送给本地邻居。

当链路成本下降时(“好消息”),所有节点重新计算最终距离向量的速度相对较快。例如,XY 链路成本从4降到1,信息在约2次迭代(与网络直径相关)后就在全网传播完毕,算法快速收敛。正所谓“好消息传得快”。

当链路成本上升时(“坏消息”),则可能出现计数到无穷大问题。考虑一个例子:XY 之间的链路成本突然增加到60(远高于通过 Z 的路径成本5+1=6)。Y 发现直接链路变贵,于是决定通过 Z 路由到 X,并更新自己的距离向量为6,然后通知 ZZ 收到更新后,发现通过 YX 的成本变成了6+1=7,于是更新自己的距离向量为7,并通知 YY 收到后,发现通过 ZX 的成本变成了7+1=8,于是又更新为8……如此循环,成本会缓慢地(本例中每次增加2)计数增加,直到最终超过直接链路的60,这个过程可能需要很多次迭代。如果成本增加到600万,则需要数百万次迭代。虽然有解决计数到无穷大问题的方法(如毒性逆转、水平分割),但这个例子说明了分布式算法的操作和可能出现的异常情况有时非常微妙。

链路状态 vs. 距离向量:对比总结📊

让我们通过比较链路状态和距离向量算法来结束对路由算法的讨论。

以下是两种算法在几个关键维度的对比:

  • 消息复杂度
    • 链路状态:需要泛洪链路状态信息,复杂度约为 O(n * e),其中 n 是节点数,e 是边数。在最坏情况下(全连接网络)接近 O(n^2)
    • 距离向量:每次迭代,节点可能需要与所有邻居通信。信息传播需要的时间与网络直径相关,约为 O(d),其中 d 是直径,在最坏情况下 d 可接近 n
  • 收敛速度
    • 链路状态O(n^2) 的计算和通信复杂度。可能存在振荡。
    • 距离向量:收敛时间可变。在收敛过程中可能出现路由环路(如计数到无穷大问题)。
  • 健壮性(路由器故障或遭破坏)
    • 链路状态:路由器可能广播错误的链路成本。但由于每个路由器独立计算自己的路由表,故障的影响相对局部化。
    • 距离向量:路由器可能广播错误的路径成本(例如,声称到所有地方的成本都非常低,这被称为“黑洞路由”)。由于每个路由器的距离向量被其他路由器使用,错误会通过网络传播,因为其他路由器会基于错误信息更新并广播自己的新距离向量。互联网历史上曾发生过因小型ISP错误配置路由器,广播了到达大型ISP(如AT&T)的零成本路径,导致大量流量被吸引到该小型ISP并被丢弃(黑洞)的真实案例。

本节课中我们一起学习了距离向量路由算法(贝尔曼-福特算法)。我们理解了其核心的贝尔曼-福特方程,掌握了算法的三个迭代步骤,认识了其信息扩散的本质和异步收敛的特性,并通过例子分析了链路成本变化时算法的行为,特别是“计数到无穷大”问题。最后,我们将其与链路状态算法在消息复杂度、收敛速度和健壮性方面进行了对比。在接下来的章节中,我们将看到这些路由算法在互联网路由协议(OSPF和BGP)中的具体实现。

5.3:开放最短路径优先 (OSPF) 🛣️

概述

在本节中,我们将学习如何将之前讨论的路由算法理论付诸实践。我们将重点关注两个关键的实际考量因素:规模自治。我们将深入探讨用于网络内部路由的开放最短路径优先 (OSPF) 协议,并了解其如何解决大规模网络环境下的路由问题。


从理论到实践

上一节我们主要从理论角度研究了路由,探讨了集中式和分布式路由算法,用于计算从源到目的地的最小成本路径。本节及下一节,我们将着眼于如何将这些原理应用于实践。

我们将从两个特定的考量因素开始:规模自治。这两个因素在将路由原理付诸实践时至关重要。对于规模,我们需要解决当存在数十亿个需要路由的端点时如何进行路由的问题。自治则涉及允许网络管理员和运营商选择在其自身网络内部以及到远端网络的路由方式。

这里我们将介绍两种路由协议:用于控制网络内部路由的开放最短路径优先 (OSPF) 路由协议;在下一节中,我们还将介绍用于网络间路由的边界网关协议 (BGP)

现在,让我们从探讨规模和自治问题开始。


规模与自治的挑战

到目前为止,我们对路由算法的研究相当理想化。我们将网络视为由链路连接的无差别路由器海洋,目标仅仅是找到从源路由器到目的路由器的最短路径。然而,在实践中,情况要复杂一些,复杂性主要源于规模问题。

我们如何路由到数十亿台终端主机和数十万个目的网络?试想一下,路由器的转发表不可能为所有目的主机保存数十亿个转发条目。而且,当我们考虑路由算法与数百万个其他实体交换距离矢量或链路状态信息时,这根本无法扩展,仅用于控制目的就会耗尽网络内的所有带宽。

其次是自治问题。这一点可能不那么明显。请记住,互联网是网络的网络,每个网络都有其所有者/运营商。网络所有者/运营商在多大程度上可以或应该被告知如何路由流量?一个网络在其路由方面拥有多大的自治权?

我们将看到,互联网的方法是双重的:首先,一个网络可以在其自身网络内选择使用任何它想要的路由协议;其次,一个网络将能够控制来自其客户网络的流量如何路由到目的地,以及它作为一个网络如何路由其他网络发送给它的流量。

让我们从规模问题开始探讨。


互联网的解决方案:分层与聚合

互联网解决路由规模问题的方法始于将路由器聚合到网络或区域的概念,这些区域有时被称为自治系统 (AS)

我们将看到,基本上有两种类型的路由:用于域内路由的路由协议和用于域间路由的路由协议。并且,我们将看到每种都有不同的协议。让我们从网络内部、自治系统内部的路由概念开始。这被称为域内路由

在域内路由中,域内、自治系统内、网络内的所有路由器都运行相同的路由协议。但是,不同的网络、不同的自治系统可以选择自己的域内路由协议。我们将看到,每个自治系统的边缘是一种特殊类型的路由器,称为网关,它将一个自治系统连接到另一个。


域间路由

然后是自治系统间 (Inter-AS) 路由,也称为域间路由,用于自治系统之间的路由。在这里,一个网络的网关将执行域间路由,并参与其自身自治系统内的域内路由。

下图展示了一个包含三个自治系统(AS1、AS2 和 AS3)的网络,即三个互连的网络。每个 AS 都有自己的域内路由协议,每个 AS 可以使用不同的域内路由协议,这对其他 AS 来说并不重要,因为那只是域内路由。

我们看到,域内路由协议负责域内和域间的路由。域内路由协议将用于填充路由器对于网络内部目的地的转发表。但是,对于发往网络外部的流量呢?在这里,域内路由协议以及部分域间路由协议将用于填充路由器对于网络外部目的地的转发表。

让我们从路由和转发到域内目的地的案例开始,因为这相对简单一些。


主要的域内路由协议

在实践中,只有三种域内路由协议被广泛采用。

第一种是路由信息协议 (RIP)。RIP 发明于 20 世纪 80 年代初,并在 RFC 1723 中标准化。它是一个经典的距离矢量协议,距离矢量信息每 30 秒定期交换一次。它在 80 年代、90 年代和 2000 年代初期被广泛使用,但 RIP 最终被开放最短路径优先 (OSPF) 协议取代,成为主流的域内路由协议。

OSPF 是一个经典的链路状态协议,它使用 Dijkstra 算法计算最短路径。还有一个相关的协议称为中间系统到中间系统 (IS-IS) 路由协议,它与 OSPF 非常相似,几乎相同,但由国际标准化组织 (ISO) 而非 IETF 标准化。

接下来,我们将更仔细地看看 OSPF,因为目前它确实是实践中最广泛部署的域内路由协议。

第三种常用的域内路由协议是增强型内部网关路由协议 (EIGRP)。它也是基于距离矢量的,实际上在数十年里曾是思科的专有协议,外界无法确切知道 EIGRP 的内部机制。然而,思科在 2013 年开源了 EIGRP,使其成为一个开放协议。

现在,让我们来看看开放最短路径优先 (OSPF) 路由协议。


OSPF 协议详解

“O”代表“开放”,意味着其规范是公开可用的。OSPF 是一个经典的链路状态协议。每个路由器将在整个自治系统内泛洪 OSPF 链路状态通告。也就是说,每个 OSPF 路由器将泛洪其每个所连接链路的信息,这些信息将传播到自治系统中的所有其他路由器。

因此,与经典的链路状态算法一样,每个路由器都拥有完整的拓扑信息。然后,OSPF 使用 Dijkstra 类算法计算每个转发表。

可以使用多种链路成本度量标准。例如,可用带宽和链路相关的延迟就是两种链路成本度量标准。最后,OSPF 最近最重要的创新之一是所有 OSPF 消息都经过认证,这是一项必要的创新。


OSPF 的层次化模式

OSPF 还可以在所谓的层次化模式下运行。OSPF 层次结构有两个级别:区域骨干

在下图中,您可以看到三个区域:区域 1、2 和 3,以及一个骨干。作为经典链路状态算法一部分的链路状态通告现在将仅在区域内或骨干内泛洪。因此,您可以看到这种层次结构如何限制在整个层次化网络中路由器之间流动的信息量。

每个节点将拥有其所在区域或骨干内的完整拓扑的详细信息。那么,问题是如何路由到不属于您区域或不在骨干中的其他节点?这就是区域边界路由器的作用。

以下是区域边界路由器的工作方式:

  • 区域边界路由器将汇总到其自身区域内其他目的地的距离,并将此信息通告给骨干中的其他节点。
  • 区域内的本地路由器将像经典的链路状态算法一样运行:在区域内泛洪链路状态信息,计算区域内的路由,并将需要发送到区域外的数据包转发给区域边界路由器。

在骨干中,我们看到两种类型的路由器:

  • 边界路由器:用于将此层次化 OSPF 网络连接到更大的外部世界,即连接到其他自治系统。
  • 骨干路由器:在骨干内运行 OSPF,泛洪链路状态信息,但仅在骨干内进行。

总结

本节是我们关于互联网路由协议实践的两部分内容中的第一部分。我们看到了规模自治问题在设计互联网路由工作原理时是多么重要的考量因素。我们深入了解了目前互联网中广泛使用的一种域内路由协议——开放最短路径优先 (OSPF) 协议。

在下一节中,我们将探讨一种域间路由协议——边界网关协议 (BGP)。互联网中只使用一种域间路由协议,因此 BGP 有时被称为“将互联网粘合在一起的胶水”,因为是 BGP 决定了如何在独立的自治系统之间进行路由。

5.4:边界网关协议(BGP)🚀

在本节中,我们将学习边界网关路由协议(BGP)。BGP是当今互联网中实际使用的域间路由协议,因此有时被称为将互联网——这个网络的网络——粘合在一起的“胶水”。

上一节我们介绍了OSPF,它是一个对Dijkstra链路状态路由算法的相当直接的实现。BGP则起源于距离向量算法。除了研究BGP如何实现和运作,我们还将花大量时间探讨BGP如何允许网络运营商实施路由策略,以控制进出其客户网络的流量路由,以及网络如何处理中转流量。我们将看到,BGP既关乎性能,也同样关乎策略。这非常有趣。

那么,让我们从BGP基础概述开始。

BGP基础概述 🌐

BGP是一个非常重要的协议,其重要性可与IP协议相提并论,可以说是互联网最重要的两个协议之一。我们将看到,BGP起源于距离向量协议,它是分布式的、异步的。但如前所述,BGP既关乎计算源到目的地的最小成本路径,也同样关乎策略。

BGP允许一个网络向互联网的其余部分宣告其存在,以及它到达这些目的网络的路径。它允许一个BGP路由器说:“嘿,我在这里,我能到达谁,特别是,我到达这些目的地的路径是这样的。”

让我们稍微展开解释一下。这意味着,在接收端,BGP为每个自治系统(AS)提供了从其邻居获取目的网络可达性信息的手段。然后,路由器可以根据策略决定是否实际使用这些路径。例如,策略可能是不使用经过某个特定ISP或特定国家的路径。

BGP还为每个自治系统提供了向其内部路由器传播可达性信息的手段。与自治系统内部路由器的这种通信通过内部BGP(IBGP)协议完成。

最后,还有一个非常微妙但非常强大的策略问题:一个自治系统希望向其邻居传递哪些目的可达性信息。如果我是自治系统,并且我知道我能到达目的地X,我真的想告诉我的邻居网络我能到达X吗?如果告诉了,它们可能会尝试通过我路由数据包去X,而也许我并不希望这样。因此,你可以看到,自治系统宣告哪些路径以及选择使用哪些路径,都涉及策略考量。

下图展示了BGP的两种类型:外部BGP(EBGP)运行在不同自治系统的两个路由器之间;内部BGP(IBGP)运行在同一自治系统的两个路由器之间。如图所示,网关路由器同时运行EBGP和IBGP。

接下来,让我们看看两个相互交互的BGP路由器(有时称为BGP对等体或BGP发言者)。BGP对等体通过半永久性的TCP连接(使用端口179)交换BGP消息。它们宣告到达不同目的网络前缀(例如,/24/16网络)的路径。因此,由于BGP宣告路径,它有时被称为路径向量协议

在这个例子中,当网络X连接到AS3时,AS3现在知道它可以到达X。因此,这里的AS3网关路由器3A向AS2的网关路由器2C宣告路径AS3, X。这样,AS2就通过AS3知道了X的可达性。需要注意的是,当AS3宣告到X的路径时,它本质上是在向AS2承诺,它既有能力也愿意向X转发数据报。

让我们通过列出BGP协议使用的消息来结束对BGP基础的讨论。有OPENNOTIFICATION消息用于打开和关闭BGP会话;KEEPALIVE消息用于在无活动时保持连接;然后是至关重要的UPDATE消息,用于宣告一条路径或撤销先前宣告的路径。你可以在RFC 4271中阅读所有关于BGP消息的详细信息。

好的,BGP的基础知识就到这里。接下来,我们将更深入地探讨BGP的一些细节,特别是路径宣告的概念,以及如何利用路径宣告来控制路由策略。

路径宣告与路由策略 ⚙️

让我们通过观察路径宣告本身来开始对路径宣告的研究。当一个BGP路由器宣告一条路径时,它宣告两样东西:首先,它宣告该路径的目的地,即目的地的CIDR地址(如/24/16);其次,它宣告与该路径相关联的一组属性。其中最重要的属性是AS路径属性,它枚举了从当前网络路由到目的网络所经过的整个自治系统列表。

我们说过BGP是基于策略的路由协议,现在我们可以确切地看到这意味着什么。首先,接收路由宣告的路由器使用策略来决定是否使用刚刚宣告给它的路径。例如,如前所述,策略可能是绝不接受经过ISP W或国家Y的路径。

路由器也使用策略来决定是否向相邻的自治系统宣告特定路径。如果我不向邻居宣告一条路径,那么该邻居永远无法向我发送使用该路径的流量,而这可能正是我想要的。

以下是一个展示路径宣告如何在自治系统之间和内部传播的例子。

假设基于策略,路由器3A决定向自治系统2(AS2)宣告一条到目的地X的路径。AS2的路由器2C通过EBGP从路由器3A接收到这个路径宣告AS3, X。基于AS2的策略,路由器2C随后接受路径AS3, X,并通过IBGP将此路径传播给所有AS2内部的路由器。

然后,基于AS2的策略,AS2的路由器2A可以通过EBGP向AS1的路由器1C宣告路径AS2, AS3, X。通过这种方式,自治系统AS1知道了通过AS2和AS3到达X的路径。

现在,一个BGP路由器有可能了解到到达同一目的地的多条不同路径,如下例所示。

在这个例子中,AS1的网关路由器1C了解到一条通过AS2和AS3到达X的较低路径。路由器1C还从路由器3A直接了解到另一条路径AS3, X(即上方的路径)。在这个例子中,基于策略,假设路由器1C选择了路径AS3, X,并通过IBGP在AS1内部宣告这条路径。

接下来,让我们看看如何利用路径宣告来实现路由策略。为了具体说明,我们假设策略如下:一个ISP只希望转发源或目的地位于其任一客户ISP网络中的数据报。这实际上是一个现实世界的策略。为什么一个ISP会想要转发仅仅是穿过的流量?这被称为中转流量。中转流量不产生收入,只有该ISP的客户网络才实际为服务付费。因此,该ISP的策略(可以理解)是只路由源或目的地位于其任一客户网络中的流量。

以下是一个例子。假设网络A、B和C是提供商网络,网络X、W和Y是客户网络。由于W是A的客户,A非常乐意向B和C宣告路径A, W。A在说:“嘿,如果你想路由到W,请通过我(A)。”确实,如果A不宣告这条路径,那么就不会有流量通过A流向W。这很合理。

但现在让我们看看在B处会发生什么。B真的想告诉C存在一条路径B, A, W吗?也许不想,因为W不是B的客户。如果B告诉C它(B)有一条到W的路径,那么C就可以通过B路由流量到W,而B没有意愿或经济动机去充当从B到A流量的中转网络。因此,B可能不会向C宣告路由B, A, W。结果,C就不知道通过B实际上存在一条到W的路径。

这是另一个基于策略的路径宣告困境。看网络X,它同时是网络B和网络C的客户。这被称为双宿主。作为一个客户,它连接到B和C,但它实际上并不希望路由B和C之间的流量,即使它可以。所以,X不会告诉B它有到C的路径,也不会告诉C它有到B的路径。结果,X永远不会承载B和C之间的中转流量。

我希望你现在能真正体会到策略在BGP中是多么重要的考量,以及ISP如何利用路径宣告作为实现路由策略的机制。对我来说,看到策略问题(而非成本)如何主导互联网中的域间路由,真是大开眼界。

现在,虽然域间路由和路径宣告决定了数据包采取的路径,但我们仍然需要解决如何填充转发表以实现与给定路径一致的转发策略的问题。让我们接下来看看这个。

转发表与热土豆路由 🥔

这个例子展示了如何使用IBGP将到达自治系统外部目的地的路径实例化到路由器的转发表中。回想一下,路由器1A、1B和1D通过来自节点1C的IBGP消息了解到如何到达X,1C说:“嘿,到X的路径经过我(1C)。”

现在让我们看看路由器1D。路由器1D从其OSPF域内路由知道,要转发数据报到1C,它应该通过接口1转发。因此,1D也知道,要转发数据报到目的地X,现在也应该通过接口1转发这些数据报,因为那是用于到达1C的接口。

在1A这边,假设OSPF域内路由表明,要到达路由器1C,1A应该使用本地接口2转发数据报。因此,1A知道要转发数据报到X,也应该通过接口2转发这些数据报。最终结果是,从1A发往X的流量将首先从1A转发到1D,然后从1D转发到1C,接着从1C转发进入自治系统AS3。

最后,有一种BGP域内路由形式被称为热土豆路由。热土豆路由说的是,当路由到一个外部目的地时,将数据包转发给我本地最近的网关,而不必担心到达目的地的总体成本。目标只是尽快将这个数据包送出我的网络。

在这个例子中,2D会将目的地为X的数据包通过2A转发,而不是通过2C。当然,这种短视的决策并不总是最佳的全局决策。在这个例子中,通过2A路由比通过2C路由涉及更多的AS跳数。这被称为热土豆路由,因为你试图以尽可能低的成本将数据包送出网络。你可能还记得小时候玩的“热土豆”游戏:你传一个球,想尽快摆脱它,以免在游戏结束时拿着球被抓住。你只是想摆脱这个球。这很有趣,它甚至让我觉得玩热土豆游戏可能比学习BGP和热土豆路由更有趣。

总结与对比 📊

这就结束了我们对BGP的讨论。我希望学习BGP和BGP热土豆路由是有趣的。让我们通过反思域内路由(如OSPF)和域间路由(如BGP)之间的一些差异,来结束我们对域间路由实践的更广泛讨论。

我们看到,在域间路由中,策略考量确实占主导地位。ISP希望拥有策略控制能力,以便能够控制如何路由进出其客户网络的流量,以及如何处理中转流量。

互联网路由的另一个关键考量是可扩展性,即关注最小化转发表大小和路由更新流量。我们了解到,域内和域间路由的分离意味着域内路由信息不会传播到自治系统之外。因此,互联网的其余部分甚至看不到任何特定域内的路由信息。考虑到构成互联网的数百万个网络,这是一件好事。

在OSPF中,我们了解了使用分层路由来限制完整拓扑信息的范围,即使在一个自治系统内部也是如此。我们在这里也了解到,以及在第4章学习互联网寻址时了解到,BGP如何路由到CIDR化的目的网络,以及一个单一的CIDR化网络地址实际上如何能代表一个地址块内的大量网络。

最后,让我们回到性能问题。我们看到在应用层、传输层甚至域内路由中,性能很重要。我们说过毫秒都很重要。但有趣的是,对于域间路由和BGP,我们看到策略考量明显优于性能考量。

这就结束了我们对互联网路由实践的讨论,特别是对OSPF和BGP协议的探讨。我希望你觉得这些内容有趣。我知道,在学习完路由算法、链路状态算法、距离向量算法,并看到它们在像RIP和OSPF这样的域内路由中实现之后,再看到在域间层面,策略而非路径成本如何主导讨论,确实有点令人惊讶。

接下来,我们将退一步,看看实现控制平面的通用方法。特别是,我们已经看到,无论是BGP还是OSPF,它们都采用每路由器的方法来实现控制平面。我们将看看另一种实现控制平面的方法,其中路径计算本身实际上在物理上从路由器中移除,可能在一个远离路由器本身的数据中心中实现。这种方法后来被称为软件定义网络。这就是接下来的内容,敬请期待。

5.5:软件定义网络与OpenFlow控制平面 🧠

在本节课中,我们将学习软件定义网络的控制平面,包括SDN控制器和OpenFlow协议。我们将探讨SDN架构如何将控制平面与数据平面分离,以及这种分离带来的优势与挑战。


概述

在之前的视频中,我们了解到互联网控制平面通常采用分布式、每路由器的方式实现。这意味着每个路由器都包含控制平面和数据平面的组件,并通过OSPF、BGP等标准化协议相互通信。然而,这种方法限制了路由器只能执行一组特定的操作,主要是基于目的地的转发。当需要其他功能时,通常需要借助非路由器的中间盒设备来实现。

过去约15年里,人们对于统一网络控制平面产生了浓厚兴趣,希望用一种设备类型来统一多种功能,提供网络层所需的大部分服务。这就是软件定义网络架构的由来,它使用具有通用转发能力的SDN交换机。

上一节我们回顾了传统路由架构,本节中我们来看看SDN架构的具体构成。


SDN架构与传统路由的对比

在传统路由器中,当数据包到达时,路由器根据其头部中的目的地址查询转发表,执行基于目的地的转发。同时,每个路由器内部实现的控制平面通过路由算法与其他路由器通信,更新转发表,从而在网络中构建通往所有目的地的连贯路径。因此,控制平面和数据平面的功能在每个路由设备内部是结合在一起的。

相比之下,SDN架构虽然也能检查数据包头部的各种字段,但它将逻辑上的数据平面功能与控制平面分离。控制平面在远程的SDN控制器中实现,这些控制器构建流表并将其下发到SDN交换机。

以下是两种架构的核心区别公式化表示:

  • 传统路由控制平面(分布式) + 数据平面(本地) = 每路由器功能
  • SDN架构控制平面(集中式,在控制器) -> [通过API] -> 数据平面(在交换机)

在这种模型中,控制平面和数据平面的功能被分离,并在不同的设备上实现。


转向SDN的动机

了解了传统路由控制平面架构后,我们现在更深入地探讨转向SDN架构的动机。

转向SDN的主要动机之一是简化网络管理,这并非出于惰性,主要是为了避免错误配置。多项对网络运营商的调查表明,错误配置是导致互联网网络中断的首要原因。因此,降低错误配置的可能性可以极大地提高互联网的可靠性。

此外,SDN还能提高流量管理的灵活性。例如,可以根据延迟或带宽的不同要求来区分不同类型的流量。

正如我们在一些分布式路由协议中注意到的,设计分布式算法很困难,在性能和实际可实现的复杂性方面都存在固有的限制。集中式编程和下发流表可以缓解这些问题,使执行复杂的路由操作变得更容易,同时仍能确保连通性不受影响。

另一个动机是通过开发开源控制器软件,向创新开放控制平面


类比:从大型机到个人电脑

从传统路由转向软件定义网络,与从集中式大型机转向分布到每家每户的个人电脑有一些相似之处。

大型机是一个整体,硬件、操作系统和应用程序都是一个生态系统的组成部分,只能彼此协作。而当个人电脑发展起来后,硬件接口被开放,使得多种操作系统可以与之互操作,并且可以在这些操作系统之上开发大量的应用程序。这导致了创新和新应用开发的爆炸式增长,这些在大型机环境中是未曾设想的。

因此,尽管尚未完全实现,但人们希望向软件定义网络的转变能带来类似的好处。


传统路由的局限性示例

以下是传统路由协议难以完成的、相对简单的流量工程任务示例。

假设从U到Z的流量按照预期沿着网络中的最低成本路径流动。然而,由于流量工程的原因,运营商需要改变这条流量的路径。在传统路由中,我们需要重新定义链路权重,使得新路径成为这两个端点之间的较低成本路径。但这显然会影响网络中的许多其他流量,而不仅仅是我们试图控制的那一条。

如果运营商不仅需要移动该流量,还需要将其拆分以分散到两条不同路径上,这就更具挑战性,需要超出典型路由协议能力的额外配置。通常,负载均衡配置会在路由协议之外构建,因为路由协议本身不直接支持该服务。

另一个例子是,我们可能有两股流量,无论出于何种原因,我们需要在W和Z之间分离这两股流量。这同样无法通过基于目的地的转发来实现。然而,通过通用转发,我们可以查看其他字段,从而实现这样的结果。


SDN架构详解

现在回到我们的SDN架构。你会注意到,在控制器之上,我们引入了一些气泡,如路由、访问控制和负载均衡,这些代表了我们需要控制器提供的逻辑功能。

在控制器内部有不同的架构,但可以将其视为在控制器上运行的应用程序,每个应用程序都为构建流表所需的信息体做出贡献。

由于OpenFlow是主流的SDN技术,我们通常使用OpenFlow术语来描述此架构的不同部分。因此,我们有位于路由器数据平面中的流表,控制平面与数据平面的分离,我们的控制平面功能,以及位于其上的控制平面应用程序。这些应用程序既可以从网络获取输入以做出情境感知决策,也可以为网络定义转发规则。

以下是SDN架构的核心组件列表:

  • 数据平面:由快速、相对简单的商用交换机组成,运行通用转发逻辑。
  • 控制平面:在远程服务器上运行的SDN控制器,负责计算并下发流表。
  • 北向API:控制器与网络控制应用程序之间的接口。
  • 南向API(如OpenFlow):控制器与SDN交换机之间的标准化接口。
  • 网络控制应用程序:实现路由、防火墙、流量工程等逻辑功能的程序。

SDN控制器详解

让我们更详细地剖析SDN控制器。虽然具体细节因控制器而异,但通常控制器会具有模块化结构,并处理一系列关注点。

控制器将包含专门用于与交换设备通信的组件,例如使用OpenFlow协议,可能还包括SNMP(简单网络管理协议)。控制器还需要跟踪网络状态,例如哪些物理链路已连接,哪些交换机已向此控制器注册。此外,控制器应知道已向交换机发布了哪些流表,并读取这些流表返回的关于设备使用情况和网络流量流的统计信息。

然后,我们有与网络控制应用程序交互的API层。这些API可以相对简单,也可以提供更丰富的网络状态视图。例如,网络图抽象、RESTful API以及某种策略意图的概念。


OpenFlow协议

OpenFlow协议用于交换机和控制器之间的连接。它在TCP上运行,较新版本支持加密。

我们可以将OpenFlow消息分为三类:

  1. 控制器到交换机消息:例如部署新的流表规则。
  2. 异步消息:交换机主动向控制器提供某些信息。
  3. 对称消息:例如控制器向交换机查询信息。

这与OpenFlow API不同,后者用于指定我们在研究SDN数据平面时讨论的通用转发操作。

以下是关键的控制器到交换机消息示例:

  • Features Request:控制器询问交换机支持哪些功能。
  • Configuration:控制器请求或设置交换机的特定配置状态。
  • Modify-State:用于操作流表。
  • Packet-Out:控制器可以封装一个数据包并将其发送到交换机,指示交换机从特定端口发出该数据包。

以下是关键的交换机到控制器消息示例:

  • Packet-In:交换机收到一个不知如何处理的数据包,将其封装后发送给控制器做决定。
  • Flow-Removed:通常表示特定流规则已超时,并从交换机的流表中删除。
  • Port-Status:交换机通知控制器其端口状态发生变化。

当然,网络运营商并不直接发送或接收这些消息,他们依赖控制器提供的抽象来生成和解释消息。


交互示例:链路故障处理

让我们跟踪一个架构内的交互示例。假设网络中发生链路故障,S1和S2之间的链路中断。S1通知控制器其端口状态变化,控制器更新链路状态信息。该信息向上传播到网络图抽象,可以被运行为应用程序的分布式链路状态路由算法使用,从而为S1计算新的流规则。

这些新规则被发送到控制器中的流表状态维护模块,然后传播到路由器。


主流SDN控制器

就像PC可以运行不同的操作系统一样,也有不同的供应商提供SDN控制器软件。

其中之一是OpenDaylight控制器。它提供基本的网络功能以及一些增强服务。它有一个服务抽象层,使用我们讨论过的一些方法与交换机进行消息传递,并向可构建在此控制器之上的应用程序暴露RESTful API。

另一个可用的控制器是ONOS控制器。它基于一个分布式核心,用于跟踪网络状态,包含对网络中链路和设备的多种抽象,并支持与这些设备的开放通信。它还支持一个意图框架,旨在允许网络控制应用程序提供所需服务的高级规范,而无需提供如何实现该服务的细节。同时,它非常重视通过分布核心来提高可靠性。


SDN的挑战与未来

然而,软件定义网络远非成熟的科学,仍有许多工作要做,特别是在防止控制平面成为网络中的单点故障方面。攻击者无疑会希望攻击这些控制器,以控制网络或导致服务中断。

虽然安全性并非从一开始就内置(OpenFlow最初甚至不支持加密),但在这方面已取得长足进步。现在,交换机和控制器之间的通信已经得到保护(假设运营商已更新到较新版本的OpenFlow协议)。然而,这从根本上仍然是基于IP的,因此在提供服务质量保证方面仍然存在挑战。

同样重要的是要认识到,SDN主要是传统域内路由的替代方案,并未直接解决是否或如何替代域间路由(如BGP)的问题。因此,SDN的优势难以跨越自治系统边界。然而,在单个提供商网络内部,SDN正得到越来越广泛的部署,尤其是在移动提供商领域。

我们一直在讨论SDN能够集中计算路由表,以及这可能比分布式路由提供的优势。但这只是一个例子。人们还可以设想使用SDN来提供拥塞控制,而不是依赖端点来猜测如何进行拥塞控制。但从根本上说,目前尚不清楚未来的SDN服务将如何发展,以及它们将如何与已建立的网络协议交互。


总结

本节课中,我们一起学习了软件定义网络的控制平面。我们探讨了SDN架构如何将控制平面与数据平面分离,介绍了SDN控制器、OpenFlow协议以及网络控制应用程序的角色。我们分析了转向SDN的动机,包括简化管理、提高灵活性和促进创新,同时也审视了SDN面临的挑战,如安全性、单点故障以及与现有域间路由协议的集成问题。在下一讲中,我们将探讨互联网控制消息和网络管理。

5.6:Traceroute、ICMP与SNMP - IP网络管理 📡

在本节课中,我们将学习IP网络管理的核心机制。我们将从ICMP(互联网控制消息协议) 开始,然后探讨其他管理工具,如SNMP(简单网络管理协议)。这些协议是网络诊断和运维的基础。


ICMP:互联网控制消息协议

上一节我们介绍了网络管理的整体概念,本节中我们来看看最基础的网络层信令协议——ICMP。

ICMP被IP主机用来传递网络层相关的信息,最常用于错误报告。例如,报告“主机不可达”或“网络不可达”等网络层错误,或与更高层相关的消息,如“端口不可达”或“协议不可达”。

我们可能都熟悉 Ping 应用程序,它使用一种特定的ICMP消息,称为 Echo Request(回显请求),该消息会触发 Echo Reply(回显应答) 消息。因此,ICMP除了错误报告外,还具有一些诊断功能。

需要注意的是,ICMP是一个带内信令协议,这意味着ICMP消息被封装在IP数据包内部进行传输。因此,如果错误导致IP层连接中断,那么由此产生的任何ICMP消息也将无法送达。

ICMP包含许多不同类型的消息,但它们都由一个类型(Type) 字段和一个代码(Code) 字段组成。由于它们通常由某个IP数据包触发,因此ICMP消息的有效载荷会“引用”触发该错误消息的数据包的前面部分。

以下是部分常见的ICMP消息类型:

  • 类型3消息:指示触发它的数据包的目的地(网络、主机、端口或协议)不可达。
  • 类型8/0消息:Ping应用使用的Echo Request和Echo Reply消息。
  • 类型11消息:TTL超时消息,被Traceroute工具使用。

Traceroute的工作原理 🔍

上一节我们了解了ICMP的基本功能,本节中我们深入探讨一个巧妙利用ICMP协议的工具——Traceroute。

Traceroute应用与ICMP的行为紧密耦合,但它并非按ICMP最初的设计意图来使用。Traceroute本质上是一个存在了数十年的“技巧”,它允许用户获取其数据所经路径的拓扑信息。

Traceroute在不同操作系统上的实现会发送不同类型的探测包,这些包可以是TCPUDPICMP数据包。另一个变量是每个TTL值是发送一个还是多个探测包。无论如何,第一组数据包的TTL都会被设置为1

这意味着它们将在第一跳就过期,导致路径上的第一个路由器生成 ICMP TTL超时 消息。

源主机发送目的地址为目标主机的数据包,但收到的却是包含ICMP错误消息的数据包,且这些数据包来自路径中间的路由器。这使源主机获得了之前未知的信息:路径中间存在一个具有特定IP地址的路由器接口。

以下是Traceroute(以每跳发送3个UDP探测包为例)的工作步骤:

  1. 源主机发送3个TTL=1的UDP数据包。第一个路由器将TTL减至0,丢弃数据包,并发回3个ICMP TTL超时消息。源主机记录该路由器的IP地址和往返时间。
  2. 源主机发送3个TTL=2的UDP数据包。第一个路由器将TTL减为1并转发,第二个路由器将TTL减至0,丢弃数据包并发回ICMP TTL超时消息。源主机记录第二个路由器的信息。
  3. 源主机持续发送TTL递增的数据包,逐步发现路径上的每一个路由器。
  4. 最终,UDP探测包会到达目的地。这些UDP数据包的目的端口被故意设置为一个预期不会被使用的端口号,因此该端口是关闭的。这将导致目的主机生成 ICMP端口不可达 消息。
  5. 源主机上的Traceroute应用收到此消息,便知道已到达目标地址,并停止探测。

这个工具对网络运维人员甚至终端用户都非常有用,可用于诊断或了解特定网络路径的性能特征。它不仅能揭示路径上的跳数及各路由器的IP地址,还能显示源主机到每个路由器的往返时间,从而帮助用户推断距离或观察路径上是否存在拥塞。


网络管理概述

在简要概述了主要用于错误报告的ICMP之后,我们现在来看看一些专门用于网络管理和配置的协议。

首先,我们明确一下“网络管理”的含义。网络通常是由自治系统(AS) 或域管理的复杂系统,其内部可能包含数十万甚至上百万个网络基础设施组件。

网络管理的定义是:对硬件、软件和人力要素进行部署、集成和协调,以监控、测试轮询、配置、分析、评估和控制网络及元素资源,从而以合理的成本满足实时运行、性能和服务质量要求。

正确执行网络管理非常具有挑战性。让我们先看看网络管理的一些组成部分。

一个典型的网络管理体系结构包括:

  • 管理服务器:维护所需状态,并提供供网络管理员交互的界面。
  • 被管设备:包括二层交换机、三层路由器、主机、中间盒等。每个设备都维护其配置、使用统计数据和特定于该设备的操作数据。
  • 管理协议:运行在管理服务器和每个设备之间,定义查询、配置消息和报告消息如何在设备与控制器之间交换。

这可以像管理员使用命令行界面登录设备进行配置和读取状态统计信息一样简单(通常是设备初始配置的方式)。但也有更专业的协议,如简单网络管理协议(SNMP),它使用标准化格式发送控制消息和读取状态,便于一次性管理大量设备。


SNMP:简单网络管理协议

上一节我们介绍了网络管理的架构,本节中我们聚焦于一个经典的管理协议——SNMP。

SNMP已经发展了多年,是一个相对简单且已使用了约三十年的协议。使用SNMP交换的信息存储在 MIB(管理信息库) 中,这是一种基于键的简单数据结构。

SNMP交换MIB中数据的方式有两种:

  1. 查询-响应:服务器主动查询设备,这是一种直接的请求-响应行为。传统上通过UDP执行,如今SNMP也支持TCP。
  2. 陷阱(Trap)消息:由设备主动发起,由某些外部事件(如定时器或设备上的特定条件)触发,向控制器发送未经请求的消息。

SNMP的主要消息类型包括:

  • GetRequest, GetNextRequest, GetBulkRequest:控制器从代理处获取数据。由于MIB可能很大,可能需要多次请求。
  • SetRequest:控制器更改代理的配置。
  • Response:代理对Get或Set消息的回复。
  • Trap / InformRequest:由代理主动发起的消息(InformRequest需要确认)。

SNMP消息格式通常包括:消息类型、请求ID(用于匹配请求和响应)、错误状态,以及一系列键值对(对象标识符OID和值)。Trap消息的头部略有不同,包含陷阱类型和时间戳。

代理在MIB中存储其收集的数据。这些信息有些是通过RFC标准化的,但许多厂商也扩展了自己的专有信息类型。数据定义语言称为 SMI(管理信息结构)

例如,针对UDP协议的MIB可能包含:

  • 计数器:记录接收到的UDP数据报数量、生成的“端口不可达”消息数量、因其他原因(如校验和失败)未能交付的UDP数据报数量,以及发送的UDP数据报总数。
  • 序列:列出当前正在使用的所有UDP端口号列表。

Netconf与YANG:现代网络管理

上一节我们探讨了传统的SNMP,本节中我们看看更现代的网络管理方法——Netconf协议及其数据建模语言YANG。

Netconf 的目标是采取更主动的管理方式。SNMP主要处理静态信息快照的报告,而Netconf定义了许多与配置设备相关的操作(例如,设置新配置并激活它),并且允许跨多个设备同时执行操作。相比之下,SNMP协议一次只与一个设备交互,跨设备聚合功能需要依靠运行在SNMP之上的应用程序来完成。

Netconf也具备从设备查询操作统计数据和信息的能力,在这方面可以取代SNMP协议。Netconf遵循 RPC(远程过程调用) 范式,其协议消息使用 XML 编码,并通过TCP进行加密传输。

一个Netconf会话交换示例如下:

  1. 控制器和代理首先交换 hello 消息。
  2. 进入一系列的远程过程调用和回复。
  3. 代理可以发送 notification(类似于SNMP的Trap消息)。
  4. 会话结束时,交换 close-session 消息。

Netconf可以执行的操作示例包括:

  • get-config:从设备检索配置。
  • get:获取特定值的状态。
  • edit-config:修改运行中的配置。
  • lock / unlock:锁定或解锁部分数据存储。
  • create-subscription:创建对事件通知的新订阅。

这些消息的结构由 YANG 指定,YANG是一种数据建模语言。例如,设备的YANG描述可以生成一个指定该设备功能的XML文档。这些信息存储在设备和控制器的数据库中,并在消息中交换。形式化这种描述允许表达约束或依赖关系,确保配置必须满足这些约束。


总结与展望

本节课中,我们一起学习了网络层的控制平面收尾部分:ICMP 和网络管理协议(SNMPNetconf/YANG)。

ICMP是网络层重要的信令协议,用于错误报告和诊断(如Ping和Traceroute)。SNMP作为经典的网络管理协议,通过查询和陷阱机制管理设备状态。而Netconf和YANG提供了更现代、基于配置和模型的集中式管理框架。

至此,我们完成了对网络栈中一个重要层边界的探讨。到目前为止,我们关注的协议(应用层、传输层、网络层)都是跨越网络端到端的。然而,当我们进入数据链路层(第2层) 时,我们将关注更局部化的网络视图,以及针对特定场景(如有线以太网、无线蜂窝链路)的技术,而IP网络层则在这些异构技术之上提供了一个统一的协议。

在下一讲中,我们将开始学习一些第2层技术及其适用场景。

5.6:ICMP互联网控制报文协议 🔧

在本节中,我们将学习互联网控制报文协议。ICMP主要用于主机和路由器之间传递网络层信息,特别是错误报告。用户通常不会直接感知到它,除非使用像Ping或Traceroute这样的工具。作为网络学习者,了解ICMP的基础知识很有必要。好消息是,本节内容非常简短,因为协议本身很简单。

ICMP协议被主机和路由器用来相互通信,传递网络层信息。这些信息通常以错误报告的形式出现,例如网络、主机、端口或协议不可达。ICMP报文也用于Ping和Traceroute工具。


ICMP报文直接作为有效载荷封装在IP数据报内部,就像UDP和TCP段一样。从这个角度看,我们可以将ICMP视为UDP或TCP的兄弟协议,但它并不被视为传输层协议。作为一个上层协议,ICMP也有一个协议号:协议号1。这个协议号用于IP层的解复用,以确定将数据传递给ICMP、UDP还是TCP。

一个ICMP报文包含一个1字节的类型字段、一个1字节的代码字段、一个2字节的校验和字段,然后是报文头以及触发该ICMP报文的原始IP数据报的前8个字节。例如,它可能包含TTL超时的数据报的前8个字节。


你可能已经注意到,类型11,代码0 对应的是ICMP TTL超时报文。这意味着路由器收到了一个数据报,将其TTL字段减1后,TTL值变为0。这个报文是Traceroute工具工作原理的关键。


有了以上背景知识,你现在应该能理解Traceroute程序的工作原理了。

Traceroute通过向目的地发送一系列(通常是三个)UDP数据报来工作。第一组数据报的IP TTL字段值设置为1,第二组设置为2,第三组设置为3,依此类推。请记住,路由器在转发数据报时总是需要将TTL字段减1。当TTL字段减至0时,该数据报必须在该路由器处被丢弃,并且该路由器可能会向源地址发回一个ICMP报文,指示TTL值已过期。

包含此ICMP TTL超时报文的IP数据报的源IP地址,就是丢弃该数据包的路由器的IP地址。因此,如果发送方发送一个TTL值为N的UDP段,那么回复的路由器就是通往目的地路径上第N跳的路由器。

这里我多次使用了“可能”这个词,因为RFC 792并不强制要求路由器必须发送ICMP报文,它只是说“可以”发送。在Traceroute中,源主机还会记录从发送IP数据报到从路由器收到相应ICMP报文所经过的时间,这测量了从主机到该路由器的往返时间。

当发送的UDP段最终到达目的主机时,该目的主机通常会返回一个类型3,代码3的ICMP端口不可达报文,但这也不是强制的。如果源主机收到了这个端口不可达报文,它就知道已经到达了路径的终点。


正如我所承诺的,本节内容简短而精要。我们可以将ICMP视为一种可用于网络管理的工具。像Ping和Traceroute这样的工具已经被网络管理员使用了数十年。然而,除了Ping和Traceroute之外,还有更多用于网络管理的工具和技术,我们将在下一节中介绍它们。


总结

本节课我们一起学习了互联网控制报文协议。我们了解到ICMP是封装在IP数据报中的协议,主要用于传递网络层信息,特别是错误报告。我们探讨了其报文格式,并详细解释了Traceroute工具如何利用ICMP TTL超时报文来探测网络路径和测量往返时间。ICMP是网络诊断和管理的基础工具。

6.1:链路层简介 🧩

在本节课中,我们将要学习计算机网络协议栈中的最低层——链路层。我们将回顾一些已学过的概念,如可靠数据传输和流量控制,但这次是在直接相连的节点之间。更重要的是,我们将探讨许多新的、有趣的主题,例如多路访问问题、局域网、链路层寻址以及数据中心网络。我们还将学习这些原理在实际协议中的具体实现,例如以太网、地址解析协议(ARP)和多协议标签交换(MPLS)。


链路层学习目标 🎯

上一节我们介绍了链路层的基本概念,本节中我们来看看学习链路层的具体目标。与学习其他层一样,我们的目标包括理解其原理实践

以下是本部分将涵盖的核心内容:

  • 原理方面

    • 差错检测与纠正:我们将学习比传输层互联网校验和更强大的差错检测与纠正技术。
    • 多路访问问题:这是网络领域的十大核心问题之一,探讨多个节点如何共享一个公共通信信道。
    • 链路层寻址:我们将研究在链路层上下文中的寻址问题。
  • 实践方面

    • 我们将考察一些具体的链路层协议,包括以太网虚拟局域网(VLAN)多协议标签交换(MPLS) 以及数据中心网络

接下来,我们将按照这个顺序展开学习。


链路层术语定义 📖

在深入细节之前,让我们先明确一些链路层的关键术语。下图(图6.1-1)有助于我们直观理解这些概念。

以下是链路层术语的定义:

  • 节点:指我们课程中一直提到的主机路由器。在链路层上下文中,我们统一称它们为节点。
  • 链路:链路层的角色是作为直接连接两个物理相邻节点的通信信道。理解“直接连接”和“物理相邻”至关重要:
    • 两个节点可以通过一根物理导线、一条无线链路(两端各有一个主机)或一个局域网(LAN) 直接相连。
    • 关键点在于,链路层连接的两个节点之间没有任何第三层(即网络层)的路由器介入。
  • :这是链路层的协议数据单元(PDU)。在互联网环境中,一个帧通常会将一个IP数据报封装为其有效载荷。

我们可以这样总结:链路层的职责是通过一条链路,将数据报从一个节点传输到一个物理相邻的节点。这个陈述中的几乎每个词都很重要。


链路层在端到端上下文中的位置 🌍

现在,让我们将链路层置于更大的端到端通信背景中来看。如果一个IP数据报从其初始源主机传输到最终目的主机,在其整个旅程中,可能会在不同的链路上被不同的链路层协议传输。

例如,第一段链路可能使用Wi-Fi,第二段使用以太网,依此类推。不同的链路层技术提供不同的服务,并具有不同的特性(例如,链路的噪声水平如何?是否提供链路层的差错控制或差错检测与纠正?)。

我们可以用一个旅行来类比:考虑从普林斯顿到瑞士洛桑的旅行。我们可能先乘汽车从普林斯顿到肯尼迪机场,再乘飞机从肯尼迪机场到日内瓦,最后乘火车从日内瓦到洛桑。在这个类比中:

  • 游客 相当于数据报,从源旅行到目的地。
  • 端到端旅程中的单个路段 相当于通信链路,每段链路提供不同的服务(理想情况下是可靠传输)。
  • 交通方式 相当于链路层协议

链路层提供的服务 ⚙️

像任何一层一样,链路层也实现封装服务。具体来说,链路层会接收一个网络层数据报,为其添加自己的字段和头部,将网络层数据报作为有效载荷包裹起来,形成链路层帧,然后将其传递给物理层,以便通过物理介质进行比特级的传输。

链路层还提供一些我们之前未见过的新服务:

  • 媒体访问:当多个节点需要共享同一个通信信道时,它们对该信道的访问需要被协调管理。实现这一功能的协议称为多路访问协议媒体访问控制(MAC)协议。注意,这里的“MAC”不是指苹果电脑。
  • 链路层寻址:在链路层,需要一种新的寻址方案。许多链路层实现使用一个48位的MAC地址方案,这与我们之前学过的32位(IPv4)或128位(IPv6)IP地址方案是不同的。MAC地址仅在单个链路的上下文中使用,不像IP地址那样在整个网络范围内使用。
  • 可靠交付:链路层可以在相邻节点之间提供帧的可靠交付。从原理上讲,我们已经知道如何实现:使用差错检测比特、超时和重传。这些技术在有线链路上很少使用,但在无线链路上很常见,因为无线链路易受噪声和干扰影响,误码率较高。你可能会问,既然有端到端的差错控制,为什么还需要链路层的差错控制?答案是,这是一种混合策略,旨在提高效率。
  • 流量控制:确保链路层发送方的发送速率不会超过接收方链路层缓冲区的处理能力,实现发送与接收双方的速度匹配。
  • 差错检测:使用比互联网校验和更强大的差错检测与纠正码,来检测(有时是纠正)帧中的比特级错误。我们将在下一节详细学习这些技术。
  • 全双工与半双工
    • 允许数据同时双向传输的链路称为全双工链路
    • 不能同时进行发送和接收的链路称为半双工链路

链路层的实现:硬件与软件的分界 💻🔧

每个网络主机都有一个链路层。主机链路层的实现特别有趣,因为它体现了硬件软件的分工。

  • 硬件部分:链路层的较低部分(以及物理层)主要在硬件中实现,例如集成在芯片上或网络接口卡(NIC) 中,该卡连接到主机的系统总线。
  • 软件部分:链路层的较高部分(如解复用向上传递、处理中断等)则在软件中实现,通常是主机的操作系统。

如下图所示(图6.1-2),链路层是网络功能在硬件和软件之间实现分工的主要位置。

最后,我们可以跟踪数据在链路层的处理流程:

  • 发送方:网络接口将IP数据报封装进链路层帧,添加差错检测/纠正比特、链路层收发地址信息,可能还有序号、确认、流量控制等字段。然后,它将帧传递给物理层进行比特级传输。
  • 接收方:链路层从物理层接收帧,执行差错检查、流量控制等服务,最后提取出有效载荷(通常是一个IP数据报),并将其向上传递给网络层。

总结 📝

本节课中我们一起学习了链路层的简介。我们看到,其中涉及一些我们已经熟悉的内容,如流量控制、可靠数据传输、寻址和比特级差错检测,但这次有了新的视角。更重要的是,我们了解到链路层还有许多新的、有趣的原理和协议等待我们去探索。

接下来,让我们正式开始深入学习这些内容。

6.2:链路层差错检测与纠错 🔍

在本节中,我们将重新探讨一个在第三章学习UDP协议时接触过的主题:差错检测。当时我们遇到了互联网校验和,它被UDP用于检测数据报中的比特级错误。现在,我们处于链路层,同样关注帧的传输。我们将从两个方面扩展之前的讨论。

首先,我们将通过例子引入一个概念:比特级错误不仅能在接收端被检测到,还能在不重传的情况下被纠正。这是一个非常棒的想法。其次,我们将了解一种在实践中使用的、比互联网校验和强大得多的差错检测技术——循环冗余校验。内容不多,本节将简短而精炼。

差错检测场景回顾 📡

以下是我们在链路层背景下研究的差错检测场景。网络层将数据报向下传递给链路层进行传输。发送方的链路层会接收数据报,添加一些首部字段,创建一个包含D比特的帧,然后计算并附加差错检测和纠错比特(此处标记为EC)。该帧随后通过可能引入比特错误的链路进行传输。

接收方执行检查,以确定接收到的帧比特是否已损坏。我们稍后将看到这是如何完成的。如果帧通过检查,接收方将提取数据报并向上传递给网络层。否则,帧将被丢弃,或者可能像我们在第三章学习的那样,启动重传过程。

我们现在要关注的是如何执行这项检查。要理解这一点,我们需要了解在发送方,这些EC比特是如何计算的。

奇偶校验:从一维到二维 📊

我们能想到的最简单的差错检测和纠错案例是简单奇偶校验。其中,单个奇偶校验比特被设置为0或1,使得原始D比特加上这个额外奇偶校验比特的总比特数在偶校验的情况下为偶数。

在这个例子中,前D比特中有奇数个值为1的比特,因此奇偶校验比特被设置为1,使得在D+1比特中,值为1的比特总数为偶数。

在接收端,检查很简单:接收方只需判断接收到的数据(包括奇偶校验比特)中值为1的比特数是否为偶数。如果值为1的比特数是奇数,接收方知道至少存在一个比特错误。如果值为1的比特数是偶数,接收方知道要么没有错误,要么可能存在偶数个错误。这就是简单的一维奇偶校验。

我们可以将其推广到二维奇偶校验:将比特排列在如这里所示的网格上,为每一行和每一列计算一个奇偶校验比特,然后让接收方同时检查行和列的奇偶性。

我们在这里使用了额外的比特,因此你希望这种额外的开销能带来更好的保护。当然,确实如此。你现在应该能确信,二维奇偶校验总能检测出两个比特错误。但二维奇偶校验还为我们带来了更多东西,一些真正特别的东西:在发生单个比特错误的情况下,它不仅允许接收方检测到发生了比特错误,还能检测出该比特错误发生的位置,并在无需重传的情况下纠正它。这有多酷?让我们看一个二维奇偶校验的例子。

这里再次展示了我们的D比特排列成网格的情况。对于第一行,我们计算行奇偶校验比特为1;对于第二行,奇偶校验比特为0;对于第三行,奇偶校验比特为1。我们也可以计算列奇偶校验比特。

现在,假设在传输中有一个比特发生了翻转,如本例所示。在这种情况下,接收方会说:“嘿,第2行存在奇偶校验错误,第2列也存在奇偶校验错误。”因此它知道第2行第2列的比特被翻转了。错误可以在无需重传的情况下被检测和纠正。

这只是所谓的前向纠错技术的一个简单例子。它们被用于DVD、光盘、数字用户线路接入网络以及深空通信中,在这些场景下接收延迟非常长。你更愿意在接收时纠正错误,而不是请求并等待重传。这是一个完整的研究领域——纠错码。如果你热爱数学,并且喜欢具有非常实用和酷炫应用的数学,这是一个值得关注的好领域。

互联网校验和回顾 🔢

我们已经在第3.3节介绍过互联网校验和。在某些方面,校验和与奇偶校验非常相似,只不过互联网校验和不是累加比特,而是累加字节。但从概念上讲,行为是相同的:在发送方,我们简单地累加字节,计算校验和,并将校验和与待校验的数据一起发送。

接收方的操作在概念上也与我们上面看到的类似。我们已经说过并看到,互联网校验和并不是特别强大。因此,据我所知,它没有在任何链路层协议中使用。相反,在以太网和Wi-Fi中使用了一种强大得多的技术,称为循环冗余校验。

循环冗余校验详解 ⚙️

让我们来看看循环冗余校验。这里再次展示了我们想要保护的D个数据比特。CRC有一个所谓的生成器G,它是一个精心选择的、长度为R+1比特的比特模式,已经过标准化,并由所有发送方和接收方商定使用,因为双方都需要使用相同的G值。例如,CRC-32 IEEE标准有一个32比特的生成器。

这里我们看到我们想要发送的D个数据比特以及R个CRC比特。如果我们考虑这D+R个比特(给定的比特D和CRC比特R),我们首先通过将数据比特左移R位,然后通过异或操作加入R个CRC比特,来计算我们想要发送的D+R比特。

以下是发送方的操作:它将计算R个CRC比特,使得这里的这个量(即待发送的比特序列)能够被商定的生成器G精确整除

由于接收方知道G,它将接收到的比特除以G。如果余数非零,那么它就能检测到错误。CRC比我们之前研究的差错检测技术更强大,因为它们能够检测所有长度小于R+1比特的突发错误(即连续的比特错误串)。这非常强大。

正是由于这些强大的特性,例如CRC-32被用于以太网和Wi-Fi帧中,在链路层进行差错检测。

如何计算CRC比特? 🧮

但我们还有一个重要问题需要回答:发送方如何计算R?我们知道发送方希望计算R,使得发送的比特模式能被G精确整除。

让我们在这个等式的两边都异或R,得到这个式子。这实际上只是用一种数学方式说明:如果我们用G除这个量(D乘以2的R次方),R就是余数。这为我们提供了一个计算R的算法。

让我们看一个例子。这只是一个玩具示例,使用一个小的4比特生成器G。这是D,这是D左移3位后的结果。现在,如果我们想遵循这里的算法,我们用G除这个量。这里是一个执行该除法运算的动画演示,我们得到的结果——余数——就是将要发送的R值。

这就是全部内容,尽管在实践中,标准的生成器长度远不止4比特。

总结 📝

本节对链路层的差错检测和纠错进行了快速研究。我希望你发现前向纠错的概念和我第一次学习时一样巧妙。我也希望你喜欢学习循环冗余校验。它有点枯燥,但确实是非常值得了解的知识,因为正如我们所看到的,CRC码在实践中被广泛使用。

6.3:多路访问链路与协议

📚 概述

在本节课中,我们将要学习链路层的多路访问链路与协议。我们将从广播链路的基本概念开始,然后深入探讨三类主要的多路访问协议:信道划分协议、随机接入协议和轮询协议。最后,我们将以有线电视接入网络为例,看看这些协议是如何在实际中结合应用的。


🔗 多路访问链路与广播信道

上一节我们介绍了链路层的一些基本原理,本节中我们来看看链路层中的链路类型。

链路层中的链路主要有两种类型:

  • 点对点链路:在单个发送方和单个接收方之间运行。
  • 广播链路:多个发送方和多个接收方都连接到这条共享链路上。

广播链路出现在许多不同的场景中:

  • 共享线缆,例如早期的同轴电缆以太网。
  • 共享无线电,例如4G/5G/LTE蜂窝系统、802.11 Wi-Fi网络和卫星网络。
  • 从人类的角度看,我们在鸡尾酒会、课堂等任何交谈发生的场所,都是在共享介质(空气)上进行通信。

当我们拥有一个共享的广播信道时,就需要一个多路访问协议来协调对这个共享信道的访问。广播信道的一个重要特性是,当两个或更多节点同时传输时,它们会相互干扰,我们称之为冲突。如果一个节点同时收到两个或更多信号,那么这些发送方的传输都不会成功。

因此,我们需要多路访问协议来协调网络中节点的传输。多路访问协议是一种分布式算法,用于确定节点如何共享信道,即决定单个节点何时可以传输。这个协议面临的真正挑战在于:任何关于如何共享信道的通信,都必须使用信道本身来完成,通常没有额外的带外辅助信道可用于协调。这正是多路访问问题的核心。


🎯 理想的多路访问协议

在开始研究具体的多路访问协议之前,让我们退一步思考,一个理想的多路访问协议应该具备哪些特性。

以下是理想协议应具备的特性:

  1. 高利用率:当只有一个节点希望传输时,它应该能够以信道的最大速率 R 进行传输。
  2. 公平性:当有 M 个节点希望传输时,每个节点应能获得平均 R/M 的发送速率。
  3. 完全分布式:没有特殊的中心节点来协调传输。
  4. 简单性:可能不需要时钟或时隙的同步。

多路访问协议是计算机网络课程中我最喜欢教授的主题之一,这是因为我们人类自身就有协议来管理如何共享通信介质,例如一群人想要交流时的空气。想想看,在课堂上、会议中、餐厅里,我们是如何组织、决定在特定时间由谁发言的。几乎可以肯定,你能想到的任何人类用来决定发言机会的协议,在多路访问协议中都能找到对应的类比。


📝 多路访问协议的分类

基于人类交流的类比,我们可以将多路访问协议分为三大类。

以下是三类主要的多路访问协议:

  1. 轮询协议:例如在课堂上,学生举手,老师点名后学生发言。这类似于轮询技术,由一个中心设备轮询客户端设备,询问它们是否有数据要发送。在其他轮询协议如令牌传递中,传输权被明确地从一个节点传递给另一个节点。
  2. 随机接入协议:另一种常见的人类交流方式是,当你有话要说时就直接说,没有明确的协调。这种方式有时有效,但有时会导致冲突。这种“有话就说”的方法被称为随机接入协议,在实践中被广泛使用。如果你像有礼貌的人一样,在说话前先倾听,这被称为载波侦听。如果你非常有礼貌,当别人在你说话时也开始说话,你会停止,这被称为冲突检测
  3. 信道划分协议:我们将信道在时间或频率上划分成块,并将这些时隙或频段分配给各个节点。这就像总统辩论中,每位候选人有固定的、不受干扰的两分钟回答时间,由中央控制器明确分配TDMA时隙,之后则进入可能发生冲突的随机接入阶段。

现在我们已经看到了要研究的三大类多路访问协议:信道划分协议、随机接入协议和轮询协议。接下来,让我们更深入地了解这些协议的细节及其在链路层网络中的应用。


⏳ 信道划分协议:TDMA 与 FDMA

我们将研究两种信道划分MAC协议:时分多址和频分多址。你可能还记得我们在第1章讨论接入网络时曾遇到过它们。

首先看TDMA。在TDMA中,对信道的访问被划分为轮次,每个轮次进一步划分为时隙。每个节点在一个轮次中被分配一个或多个时隙。如果时隙未被使用或分配,它们将处于空闲状态。例如,在一个有6个站点的局域网中,站点1、3、4有数据包要发送,它们就在分配的时隙中发送,而时隙2、5、6则空闲。

FDMA与TDMA类似,区别在于它将整个频带划分为多个子频带,每个节点在这个大频带内被分配一个或多个子频带。就像TDMA分配时隙一样,FDMA分配频率子带。如果一个频率子带未被分配,或者被分配的节点无数据可发,那么该子带将处于空闲状态。例如,节点1、3、4在它们的频带上发送数据,而频带2、5、6则空闲。


🎲 随机接入协议:ALOHA

现在我们已经介绍了信道划分协议TDMA和FDMA,接下来让我们把注意力转向随机接入协议。记住,在随机接入协议中,节点之间没有先验的协调,没有“轮次”的概念,因此两个或更多节点可能同时传输,导致冲突。所以,随机接入问题的核心在于找到有效的方法来避免或从这类冲突中恢复。

第一个被发明的随机接入协议是ALOHA协议,它也是最简单的协议之一,但它开创了我们在后来所有随机接入协议中都会看到的两大关键思想:

  1. 允许冲突发生:与我们刚看的TDMA和FDMA通过精心分配时隙和频带来避免冲突不同。
  2. 使用随机化从冲突中恢复

以下是时隙ALOHA的设置:假设所有帧大小相同,时间被划分为时隙,一个时隙的长度等于传输单个帧所需的时间。节点是同步的,它们有公共时钟,并且节点只在时隙开始时启动帧传输。当然,如果两个或更多节点在同一时隙传输,就会发生冲突,并且这些冲突会被发送方检测到。

时隙ALOHA的操作非常简单:

  1. 当节点有帧要发送时,它就在下一个时隙发送该帧。
  2. 如果没有冲突,则传输成功。
  3. 如果发生冲突,节点将以概率 p 在后续的每个时隙中重传该帧,直到成功。

这里就使用了随机化。冲突后,发生冲突的节点将随机化它们尝试重传消息的时间。你可以理解为什么必须这样做:如果两个节点总是在下一个时隙重传,它们将永远冲突;通过随机化(即以概率p传输),希望只有一个节点会传输并成功,而另一个节点将在之后的某个时隙传输。

随机化在许多实际的链路层随机接入协议中都有使用,包括以太网和Wi-Fi,尽管那里的随机化方式略有不同,但正是ALOHA首次将“随机”一词带入了随机接入协议。

时隙ALOHA有优点也有缺点。优点是:作为随机接入协议,单个活跃节点可以连续以信道全速传输;它是高度分布式的,节点间唯一的同步是时钟;并且它很简单。缺点是:同步有一些开销;但主要问题在于时间传输时隙的浪费,包括因冲突和空闲时隙造成的浪费。

我们可以量化这些浪费时隙的成本。定义时隙ALOHA的效率为长期成功时隙的比例。经过一些组合数学和微积分计算(对于大量节点,优化传输概率p后),我们发现时隙ALOHA的最大效率仅为 0.37。这意味着,在长期最佳情况下,只有37%的时隙能成功承载一帧。例如,对于一个1 Mbps的信道,你能实现的最大吞吐量仅为370 kbps。这就是使用时隙ALOHA协议的代价。另外,一个没有时隙边界的更简单版本称为纯ALOHA,它只是有帧就发,冲突后随机重传,其效率更低,只有0.37的一半。


🔊 随机接入协议:CSMA 与 CSMA/CD

另一类随机接入协议被称为载波侦听多路访问。这些协议可以克服ALOHA的低效性。你可以把ALOHA用户想象成不礼貌的交谈者,有话就直接说。CSMA协议则更像有礼貌的交谈者,它们在说话前先倾听。

在简单的CSMA中,你在传输前先侦听信道。如果信道空闲,你就传输整个帧(就像ALOHA一样)。如果信道忙,你就不传输,随机推迟一段时间后再尝试,这有时被称为随机退避。人类类比很清楚:你的父母和老师可能教过你,要先听再说,不要打断别人。

一个更有礼貌的CSMA版本被称为带冲突检测的CSMA。在CSMA/CD中,你从不在别人说话时说话,但如果你开始说话时,恰好别人也同时开始说话,冲突仍然可能发生。这些传输可以在相对短的时间内被检测到,然后冲突的传输被中止,从而减少了信道浪费。你不是传输完整个冲突的帧,而是在检测到冲突后立即停止。冲突检测在有线情况下相当容易,但在无线链路中则更困难。

你可能会想,CSMA作为有礼貌的交谈者,先听后说,怎么还会有冲突?毫无疑问,你都有过这样的经历:你和朋友交谈,双方都先听后说,却同时开始说话。这里的问题与传播时延和节点间的距离有关。一个节点发出的传输需要时间才能到达另一个节点。具体来说,即使一个节点侦听到信道空闲,也并不意味着另一个节点还没有开始传输,只是那个传输还没有时间传播到正在进行载波侦听的节点。

为了最小化传输时间的浪费,发送节点可以执行冲突检测:如果它听到自己的传输受到干扰,就停止传输。这样,节点只传输部分发生冲突的帧,从而更快地释放信道,这是一个优势。


🔌 以太网中的 CSMA/CD

我们说过以太网使用带冲突检测的载波侦听多路访问。让我们更仔细地看看它是如何操作的。

像任何链路层协议一样,以太网从网络层接收数据报,将其封装到链路层以太网帧中,然后准备发送该帧。以太网使用CSMA/CD来确定何时发送该帧。

以下是操作步骤:

  1. 载波侦听:如果信道空闲,立即开始传输帧。如果信道忙,则持续侦听信道,等待直到信道空闲,然后立即传输帧。
  2. 传输与冲突检测:如果整个帧传输过程中没有检测到冲突,则完成。如果在发送帧时检测到另一个干扰传输,则停止帧传输,并发送一个短的阻塞信号。
  3. 二进制退避:中止帧传输后,以太网进入二进制(指数)退避阶段。这是以太网在冲突后执行随机化的方式。

具体退避算法如下:在给定帧经历第 n 次冲突后,以太网从区间 {0, 1, ..., 2^n - 1} 中随机选择一个值 K,然后等待 K * 512 比特时间,再返回到步骤1(载波侦听步骤)。

关于这个指数退避阶段,值得多说几句。请注意,随着帧经历越来越多的冲突,很可能有更多节点有帧要发送。在这种情况下,随机化区间也会变得越来越长。这正是你想要的:当可能只有少数发送者时,在短时间段内随机化;当可能有大量发送者时,在更长时间段内随机化。我一直认为这是以太网二进制退避算法一个设计得非常巧妙、精良的特性。


🔄 轮询协议

现在我们已经介绍了两类多路访问协议:信道划分协议和随机接入协议。第三类也是最后一类广义协议是轮询协议,例如在蓝牙中使用。在深入轮询协议之前,让我们先了解一下为什么需要第三类协议。

我们看到信道划分MAC协议有优点也有缺点。优点是能高效、公平地共享信道,在高负载下信道利用率可达100%。缺点是在低负载时效率低下,访问信道有延迟,如果只有一个节点有数据,它在一段时间内只能使用1/N的带宽。

随机接入MAC协议同样有优缺点,这些优缺点与信道划分协议正好相反。它们在低负载时非常高效,冲突很少,单个节点可以独自完全利用信道。但在高负载时,会发生冲突,产生开销。

现在我们可以转向轮询协议,它试图结合前两者的优点。信道被明确分配,因此没有冲突。另一方面,如果节点没有数据要发,它不会长时间占用信道。基本上有两种方法:轮询令牌传递

轮询协议有一个中心控制器来协调对信道的访问。控制器向客户端发送轮询消息,明确将信道分配给特定客户端(如果该客户端有数据要发送)。当一个客户端发送完其帧,或者它没有数据要发送时,中心控制器将轮询轮询序列中的下一个节点,依此类推。

优点是:没有冲突,每个节点可以获得1/N的信道份额,如果节点无数据可发,它占用信道的时间很短,只有短暂的轮询延迟。缺点是:存在一些控制器开销,并且中心控制器代表了一个单点故障。

令牌传递中,节点通常排列成环形拓扑,一个控制令牌消息按照某种顺序明确地从一个节点传递到下一个节点。如果你是一个持有令牌的节点,就意味着轮到你传输消息了。当你发送完毕或没有数据可发时,你将令牌消息传递给令牌传递序列中的下一个节点,依此类推。

令牌传递具有与轮询类似的优点和缺点。需要一个加入/离开协议,存在一些控制开销和额外延迟,并且令牌本身代表了一个单点故障。


📺 实践案例:有线电视接入网络

让我们通过观察所学原理如何付诸实践来结束对多路访问协议的研究。我们将以有线电视接入网络为例,因为它在一个系统中同时使用了TDMA、FDMA和随机接入。

你可能还记得我们在第1章简要介绍过有线电视接入网络。这里有一个电缆头端,其中包含电缆调制解调器终端系统。所谓的DOCSIS规范规定了有线接入数据网络的架构及其协议。DOCSIS使用FDM将下行网络和上行网络各自划分为多个频率信道。下行和上行信道都是广播信道。下行信道相对简单,因为只有CMTS在下行信道上发送。上行信道则更有趣,因为多个家庭中的电缆调制解调器需要共享那个上行广播信道。

让我们看看上行信道。一个给定频率的上行信道被划分为TDMA时隙。你可能会问,这些时隙是如何分配的?一些上行时隙由CMTS通过发送下行MAP帧分配给节点(即家庭),该帧明确指示哪些节点可以在下一组上行时隙中的哪些时隙传输。然而,其他上行时隙没有被预分配,节点以随机接入的方式,使用二进制退避在这些未分配的帧中传输。

因此,有线网络使用FDM将频带划分为子信道,将频率子信道划分为TDM时隙。CMTS根据对时隙的请求,将其中一些时隙明确分配给特定家庭。但其他时隙则以随机接入方式访问。实际上,家庭在上行信道上发送的对这些上行时隙的请求,正是使用带二进制退避的多路接入来传输的。所以,有线网络是研究多路接入(FDMA、TDMA和随机接入)的一个绝佳例子。


📖 总结

本节课中我们一起学习了多路访问链路与协议,涵盖了大量内容。

我们首先讨论了广播信道的特性,然后研究了三大类多路访问协议:信道划分协议、随机接入协议和轮询协议。最后,我们通过观察称为DOCSIS的有线电视接入标准,了解了如何将这些协议付诸实践。

接下来,我们将学习交换式局域网。

6.4:媒体接入控制(MAC)协议 📡

在本节课程中,我们将学习媒体接入控制(MAC)协议。当多个设备需要同时使用同一个共享通信链路时,这些协议决定了如何协调设备间的数据传输,以避免冲突并高效利用带宽。

共享链路与多路访问问题 🔗

上一节我们介绍了链路层的基本概念,本节中我们来看看当链路被多个设备共享时会出现的问题。

网络链路可以分为点对点链路和广播链路。

点对点链路只连接两个设备。在实践中,这意味着一个设备的发射器连接到另一个设备的接收器,反之亦然。现代的点对点设备是全双工的,这意味着链路的每一端可以同时发送和接收数据,无需共享带宽。

另一方面,广播媒体可以在链路上连接两个以上的设备,但同一时间只能有一个设备在发送数据,否则就会发生冲突。有线以太网曾被认为是共享介质,但这主要适用于旧版本。现代有线以太网实际上由点对点链路构成。然而,为有线以太网设计的基本机制如今被用于无线以太网(Wi-Fi),即802.11系列协议。另一种至今仍在使用的共享有线媒体是电缆互联网系统,即有线电视提供商通过其同轴铜缆基础设施运行的接入网络。

总的来说,任何无线技术都必须处理在共享介质中运行的问题。

多路访问协议的设计目标 🎯

为了明确我们要解决的问题:如果我们有一个共享介质,并且有多个设备想要发送数据,如果它们的传输在时间上重叠,就会发生冲突,接收方将无法理解任何一方的传输。

因此,多路访问协议决定了多个发送方以避免冲突的方式使用共享介质。

我们还必须注意,这是一个带内协议。多路访问协议使用信道本身来决定如何使用信道,这带来了一些有趣的工程权衡。我们这样做,而不是使用单独的控制信道,因为增加一个单独的信道会大幅增加系统成本,而不会带来相应的性能提升。

假设我们的信道带宽为 R 比特/秒,我们有一些设计目标:

  1. 如果单个节点需要发送,它可以使用信道的全部带宽 R 比特/秒。
  2. 如果多个节点需要发送,它们每个节点的平均发送速率应为 R/M,这意味着信道带宽仍然被充分利用。
  3. 理想情况下,这应该使用完全分布式的算法,即不需要一个控制器节点来协调用户间的传输,也不需要昂贵的时钟同步。
  4. 我们希望协议简单且易于实现。

可以想象,其中一些目标是相互冲突的,因此找到解决方案意味着在它们之间进行权衡。事实上,有如此多的不同解决方案,我们将MAC协议分为三大类:

  • 信道划分:将可用带宽划分为预分配的块,分配给不同的发送设备。这些块可以基于时隙、频段或码点来划分。
  • 随机接入:不预先将信道划分为多个块,它允许冲突发生,但在冲突发生后采用某种恢复机制。
  • 轮流协议:不是预先进行硬性划分,而是动态地进行划分,这样就不会发生冲突,但需要发送更多数据的节点可以使用比发送数据少的节点更多的带宽。

在本视频的其余部分,我们将逐一介绍这几类媒体接入控制协议的示例。

信道划分协议 📊

首先,我们来看信道划分协议。这类协议的核心思想是将信道资源预先分配给各个节点。

时分多址(TDMA) ⏰

一种经典的信道划分方案是时分多址(TDMA)

在TDMA中,信道上的时间被划分为固定长度的时隙,每个站点获得一个时隙用于发送。这对于恒定比特率的应用(如电话呼叫)很有效,因为每次通话在通话期间持续使用相同的带宽量。

然而,我们知道互联网流量是突发性的,这意味着有时站点需要发送数据,有时则不需要。因此,当站点不需要发送数据时,它的时隙将处于空闲状态,带宽就被浪费了,因为其他站点不允许使用它。

频分多址(FDMA) 📻

另一个简单的方案是频分多址(FDMA)

在这种情况下,不是划分时间,而是将频带划分为多个信道。这正是广播电台或电视的工作原理,多个电台可以同时广播,接收器只需调谐到他们想要接收的正确频道。

同样,这适用于恒定比特率的应用,但如果某个特定的发送方没有任何东西要发送,该信道将处于空闲状态,带宽就被浪费了。

请注意,这也是广播有线网络上划分带宽的方式,这在我们后面查看HFC网络时会相关。

码分多址(CDMA)

还有另一种信道划分方案称为码分多址(CDMA),它广泛用于蜂窝网络,但我们将在下一章关于无线网络时再详细讨论。

随机接入协议 🎲

现在,我们来看看随机接入协议如何工作。

基本思想是,如果一个节点需要发送一个数据包,它就直接发送,并且以信道的全速率发送。如果另一个节点碰巧同时尝试发送,就会发生冲突,两次传输都会丢失。

因此,随机接入MAC协议需要规定如何检测冲突,以及是否应采取任何恢复措施。

最早的、最简单的随机接入MAC协议示例是ALOHA时隙ALOHA协议,它们的后继者是今天仍在使用的CSMA及其变体CSMA/CDCSMA/CA

时隙ALOHA协议

在时隙ALOHA中,我们有一些假设,包括所有帧大小相同,并且一个时隙的长度正好足够传输一帧。节点被要求只能在时隙开始时开始发送帧,以便在同一时隙内完成发送。它还要求节点同步,以便所有节点在时隙开始时间上保持一致。如果在同一时隙内有多次传输,那么所有节点都会检测到这个冲突。

以下是时隙ALOHA的工作原理:

  • 当节点有帧要发送时,它在下一个时隙开始时立即发送。
  • 只要没有冲突,它就可以继续发送新帧。
  • 然而,如果发生冲突,节点需要重传发生冲突的帧。但它不会在每个时隙都重试,而是使用一个概率 P 来决定是否在每个后续时隙中尝试,直到成功发送该帧。

为什么需要随机化?根据定义,如果发生冲突,意味着有多个节点试图在同一时隙发送帧。如果它们都在每个时隙重试,它们将在每个时隙都发生冲突,永远无法成功发送帧,这实际上会导致网络无法工作。因此,两个发送方都需要“抛硬币”决定是否重试,从概率上讲,其中一个会成功,然后另一个也会成功。

让我们看一个有三个节点在一系列时隙中发送帧的例子。我们可以看到,在第一个时隙,三个节点发生冲突,概率上三个节点都没有在第二个时隙尝试发送,所以第二个时隙是空的。然后,其中两个节点在第三个时隙再次冲突,但节点2在第四个时隙重试并成功。后来,节点1和节点3冲突,最终节点1成功,然后节点3成功。

这个系统的优点是,如果需求稀疏,一个节点可以连续以信道的全速率发送。因此,我们实现了媒体接入控制的一个设计目标。这个机制也是完全分布式的,没有主节点控制。虽然这里没有提到,但冲突检测是基于来自中央节点的确认(通过一个单独的信道返回),从这个角度来看,它没有完全满足我们的一些目标。但这个协议也非常简单且易于实现。

这个协议的缺点是,我们有冲突会浪费时隙,并且在概率性退避期间,我们也有空闲时隙被浪费。因此,在争用激烈时,这个MAC协议很快就会变得低效。我们还需要某种程度的时钟同步,以便所有发送方的时隙对齐。

我们提到了效率问题,让我们看看它到底有多糟糕。

假设我们有 N 个节点,它们在任何一个给定时隙以概率 P 发送。那么,一个发送方在任何一个给定时隙成功的概率,也是没有其他节点在同一时隙尝试发送的概率。随着节点数 N 的增加,这个概率会降低。任何节点成功的概率只是一个节点成功概率的 N 倍。因此,我们的最大效率是在找到使这个效率最大化的概率 P 时实现的。实际上,这意味着每个节点希望发送帧的频率。对于大量的节点,我们发现可达到的最大效率是 0.37,即我们可用带宽的 37%,这是最佳情况。让所有节点都以这个确切的概率 P 运行并不容易。

纯ALOHA协议

在时隙ALOHA之前,有纯ALOHA,它没有同步时钟的要求。因此,节点不是等待下一个时隙开始才发送帧,而是只要它有帧要发送就立即发送。

这种协议的性能比时隙ALOHA更差,因为可能存在部分重叠的帧,这意味着总体冲突概率更高。任何给定的帧都可能与几乎在其前后一个完整帧长度内发送的帧冲突,而不仅仅是与完全在同一时隙发送的帧冲突。如果我们计算纯ALOHA的概率,会发现它的效率正好是时隙ALOHA的一半,对于大量需要发送流量的节点,只有 18%

载波侦听多路访问(CSMA)协议

ALOHA协议的后继者是CSMA(载波侦听多路访问)。在这种情况下,发送方在开始传输之前先侦听信道,如果另一个节点已经在发送,则等待并稍后重试。

CSMA的一个变体是CSMA/CD(带冲突检测的载波侦听多路访问)。这意味着在发送时,节点可以检测到正在发生冲突并迅速停止,这样就不会浪费太多时间发送一个已经冲突且对任何人都无用的帧。然而,在实践中,CSMA/CD只能在有线网络中实现。

CSMA/CD 的工作原理

即使在载波侦听的情况下,我们仍然可能发生冲突。这是因为两个节点可能同时侦听并决定发送,并且由于传播延迟,实际上存在一个短暂的时间窗口,在此期间一个节点听不到另一个已经开始发送的节点。提醒一下,每当发生冲突时,整个数据包都会丢失。

这里我们看到,我们的一个节点开始发送,但另一个节点还没有听到,于是也开始发送。因此,当这两个传输在共享介质中传播时,它们会相互干扰,没有人能够接收这些帧。然而,由于组合的发送功率,节点可以检测到发生了冲突。

该算法的冲突检测部分意味着节点在检测到冲突后不会继续发送很长时间,因此这减少了通信信道中的时间浪费。这就是有线以太网所基于的算法。

它的工作流程如下:

  1. IP层或任何其他网络层可以将数据报传递给以太网适配器,然后适配器创建帧并侦听信道。
  2. 如果信道空闲,它可以立即开始发送。
  3. 如果信道繁忙,它将等待信道空闲。
  4. 只要传输在没有冲突的情况下完成,该帧的发送就结束了。
  5. 然而,如果检测到冲突,它会中止发送,并向线路上发送一个干扰信号。
  6. 中止发送后,适配器进入二进制指数退避状态。

就像我们之前提到的,根据定义,当发生冲突时,意味着有多个发送方试图发送。因此,如果它们都立即重试,将保证再次发生冲突,如此循环。但这种二进制指数退避以一种受控的方式来确定适配器重试的概率,这决定了适配器在返回并再次侦听信道之前等待多长时间。

在第一次冲突时,K 将从 0 到 2^1 - 1(即 0 到 1)之间的整数中随机选择。因此,适配器要么等待 0 个比特时间后再次侦听,要么等待 512 个比特时间后再次侦听。然而,如果发生第二次冲突,它将等待 0 到 2^2 - 1 倍的 512 个比特时间,即 0 到 3 倍的 512 个比特时间。因此,你可以看到,每次发生后续冲突时,等待时间的上限都会增加,以试图降低后续冲突的概率。

我们也可以对CSMA/CD进行效率分析,我们可以看到这里的限制因素是必须考虑的传播延迟。当然,我们知道传播延迟是距离的直接函数,因此共享链路越长,我们必须为传播延迟留出的时间就越多,效率就越差。然而,只要我们保持较低的传播延迟(即我们只在局域网环境中使用它),在实践中,这些共享以太网段被限制在200米,我们可以看到我们可以实现接近1的效率,比ALOHA协议好得多。

轮流协议 🔄

现在我们来看看轮流协议,这是试图在前两类MAC协议之间找到一个折中方案。

轮询

实现这一点的一种方法是轮询。我们的目标之一是没有主节点,但在这里这是必需的,因此我们在这个目标上做出妥协,以改进其他一些目标。

在轮询场景中,主节点依次询问每个设备是否有数据要发送。这里的问题是轮询需要一些时间,因此我们失去了一些效率。此外,我们有一个主节点,这是一个额外的开销,而且它可能成为单点故障。如果主节点宕机,那么没有人会被轮询,也没有人能发送数据。

我们可以看到,主节点向单个节点发送轮询请求,然后该节点可以发送数据,接着主节点轮询另一个节点,依此类推。

令牌传递

轮流协议的一个分布式版本是令牌传递

在这种情况下,节点在逻辑上排列成一个环,它们将令牌从一个节点传递到另一个节点。如果节点需要发送数据,它就发送,然后传递令牌;如果不需要发送任何数据,它就直接传递令牌。

同样,传递令牌有一些开销。当然,如果环在任何地方断开,那么系统就会宕机,因为令牌会丢失。这个节点没有数据要发送,就将令牌传递给另一个需要发送一些数据的节点,依此类推。

在实践中,轮询方案和令牌传递方案都曾被实现和部署,但采用CSMA/CD的以太网成为了市场上的主导协议。

电缆接入网络 📺

现在让我们看看电缆接入网络,它的运行距离比我们目前讨论的典型局域网更长。电缆接入网络同时部署了频分复用、时分复用和随机接入。

我们有电缆头端。电缆头端必须将互联网的数据帧和广播电视、无线电、数字电话等他们通过同轴铜缆提供的任何其他服务复用在一起。因此,这些服务都以不同的频率复用到电缆上,这就是FDM部分。我们有多个下行信道,CMTS在所有下行信道上发送数据。我们也有多个上行信道。在上行信道上,信道数量没有网络上的用户数量多。因此,头端在这些信道内分配一些时隙。然而,还有一些其他时隙未被分配,用户使用随机接入机制来争用这些时隙。

定义其工作原理的协议称为DOCSIS,多年来有多个不同版本的DOCSIS,我相信当前普遍部署的是DOCSIS 3.1。

正如我们所说,在上行和下行方向都有FDM在运行,但TDM只在上行信道上运行。CMTS发送一个称为MAP帧的帧,告诉每个用户他们被分配了哪个上行信道。但它只在用户节点请求后才分配这些信道,而这些请求是以随机接入的方式发送的,并且是在未分配给任何特定节点的时隙中发送的。

这里我们有我们的MAP帧为特定间隔分配时隙,我们有一堆用于请求帧的微时隙,用户节点可以随机选择一个来放入请求。但它们只有在被CMTS分配了上行数据时隙后才能使用这些时隙。

总结 📝

本节课中我们一起学习了媒体接入控制协议。

我们讨论了用于信道划分方案的TDMAFDMA。在随机接入方面,我们看到了ALOHA协议,它后来发展为基于CSMA的协议。我们暂时省略了对CSMA/CA的讨论,因为它目前用于无线协议,并且我们接下来有一整章关于无线网络的内容,我们将在那里介绍CSMA/CA。我们还研究了轮流协议,这些协议在实践中有效,但由于成本或其他问题,已不再广泛部署。

在下一个视频中,我们将探讨局域网的其他考虑因素,包括寻址、地址解析协议以及有关有线以太网的更多细节。

6.5:MAC地址、ARP与以太网 🖧

在本节课中,我们将学习局域网(LAN)链路层的关键概念。我们将重点探讨MAC地址、地址解析协议(ARP)以及以太网技术。这些是理解数据如何在本地网络中传输的基础。


MAC地址与IP地址的差异

上一节我们讨论了共享信道的多路访问问题,本节中我们来看看链路层协议如何处理寻址。

MAC地址的工作方式与IP地址有显著不同。作为提醒,IP地址是32位,用于第3层(网络层)转发,其转发基于最长前缀匹配。而MAC地址是第2层(链路层)地址,仅在本地使用。

在IP的语境下,MAC地址仅在一个子网内有效。目前,几乎所有的第2层技术都使用48位MAC地址。这些地址被嵌入在网络接口卡(NIC)中,可能可以通过软件更改。

MAC地址的书写格式如下,由十六进制数字对组成:

XX-XX-XX-XX-XX-XX

其中的连字符(-)仅为方便,有时也用冒号(:)代替。一个十六进制数字代表4位二进制,因此这12个字符代表了MAC地址的48位。


MAC地址的特性与示例

以下是MAC地址的一些关键特性。

  • 无结构关系:在同一局域网中,设备的IP地址共享相同的前缀,但MAC地址没有这种约束。它们看起来是随机的,彼此之间没有共同点。
  • 制造商标识:MAC地址的前几位(通常是前24位,即前6个十六进制字符)标识其制造商,这部分被称为组织唯一标识符(OUI)。制造商可以按序列或随机方式设置地址的剩余部分。
  • 精确匹配:由于MAC地址之间没有层次结构关系,当需要将帧转发到特定MAC地址时,我们不能使用最长前缀匹配,而必须进行精确匹配

MAC地址由IEEE统一分配。制造商从IEEE获得地址块(OUI),然后可以在该块内使用所有地址。这就像社会安全号码,其结构本身不包含如何找到该主机的信息。

这种设计的优势在于可移植性。MAC地址跟随设备,当设备连接到新网络时无需更改。这与IP地址形成对比,IP地址属于网络,当设备更换网络时,其IP地址会改变。


地址解析协议(ARP)

下一个问题是:我们如何找到用作帧目的地的MAC地址?设备知道自己的MAC地址(用于源地址字段),并且可以通过DNS找到目标IP地址。但如何找到用于第2层帧目的字段的MAC地址呢?

这依赖于一个名为地址解析协议(ARP) 的协议。它是一个分布式数据库查询功能,将IP地址映射到MAC地址。网络上的每个节点都必须维护一个ARP表,记录已知的IP地址与MAC地址的映射关系。与大多数映射一样,它有一个生存时间(TTL),超时后条目将被视为过时并从表中删除,常见的默认TTL是20分钟。

以下是ARP的工作过程。

  1. ARP请求(广播):当主机A需要向主机B发送数据报,但ARP表中没有B的IP-MAC映射时,A会发送一个广播ARP请求帧。第2层的广播地址是全F的MAC地址(FF-FF-FF-FF-FF-FF)。该帧询问:“谁拥有这个IP地址?”
  2. ARP响应(单播):局域网上的所有节点都会收到此广播。拥有该IP地址的主机B会向A回复一个单播ARP响应帧,其中包含自己的MAC地址。
  3. 更新ARP表:主机A收到响应后,用B的IP-MAC映射更新自己的ARP表,然后就可以使用B的MAC地址作为目的地发送帧了。

跨子网的ARP与路由器的作用

如果A和B在同一个子网,上述过程是可行的。然而,广播帧(全F的MAC地址)不会被路由器转发,因此只有同一子网内的设备能听到此查询。

考虑一个路由器在A和B之间的拓扑。如果A发送针对B的IP地址的ARP请求,它永远不会到达B,因为路由器不会转发ARP请求。这是件好事,因为它允许网络扩展。如果ARP请求被路由器转发,它们将在网络中大量传播,消耗过多带宽。

那么,A如何获得B的MAC地址呢?以下是跨子网通信时ARP和路由器的协作过程。

  1. 判断目标子网:A比较B的IP地址和自己的子网掩码,发现B在不同的子网。
  2. 寻找网关:A知道其网关路由器(第一跳路由器)的IP地址(通过管理员配置或DHCP获取)。
  3. 获取网关MAC:A通过发送ARP请求,获取网关路由器接口(在A的子网上)的MAC地址。
  4. 封装与发送:A创建一个目的IP地址为B的数据报,但在第2层,它使用网关路由器的MAC地址作为帧的目的地址。因为第2层地址仅在本地子网内有效。从第2层的角度看,路由器是这个帧的目的地。
  5. 路由器处理:路由器(第3层设备)收到帧,剥离第2层帧头,将数据报传递到IP层。
  6. 路由器转发:路由器查看数据报的目的IP地址(B),决定从连接B子网的接口转发出去。
  7. 新帧封装:路由器需要为这个数据报创建一个全新的第2层帧。它使用自己接口(在B的子网上)的MAC地址作为源地址,并需要B的MAC地址作为目的地址。路由器可以通过发送ARP请求来获取B的MAC地址(很可能B的MAC地址已缓存在路由器的ARP表中)。
  8. 最终交付:新的帧被发送到B的子网,B收到后提取IP数据报并上传给上层协议。

以太网技术详解

现在你已经了解了足够的MAC地址和ARP知识,让我们更详细地探讨一下以太网

以太网是当今主导的局域网技术。其成功很大程度上归功于其设计的简洁性,使用了基于CSMA的协议。这也帮助它跟上了速度竞赛,如今已达到每秒400千兆比特。以太网接口通常支持多种速度,允许不同速度能力的设备以较低速度通信。

早期的以太网版本是真正的总线结构,即一根长长的同轴电缆,多台计算机通过分接头接入。后来,长电缆被集线器(Hub) 取代,但功能相同,仍然是共享介质。到90年代末,交换机(Switch) 变得越来越普遍。交换机是第2层网络中的主动设备,能够分割冲突域,并在交换机与每个主机之间创建点对点链路。因此,当以太网达到千兆速度时,共享总线模型已不再使用。

在交换网络中,第2层架构以交换机为中心,绘制到每个主机的点对点链路。这些链路是全双工的,因此在完全交换的第2层网络中没有冲突。消除了冲突极大地提高了网络利用率。


以太网帧结构

以下是标准以太网帧的结构。

  • 前导码(8字节):用于接收设备同步时钟,以正确读取后续数据。
  • 目的地址(6字节):目标MAC地址。
  • 源地址(6字节):发送方MAC地址。
  • 类型(2字节)以太网类型(EtherType),提供解复用功能,指明载荷中数据的类型(如IPv4、IPv6、ARP等)。
  • 数据(46-1500字节):上层协议数据单元。
  • CRC(4字节):循环冗余校验码,用于错误检测。

网络适配器收到消息后,会检查目的地址是否与自己的MAC地址或广播地址匹配。如果匹配,则根据类型字段将数据上传;否则,丢弃该帧。这被称为广播并选择模型

与IP类似,以太网是不可靠且无连接的。帧之间没有握手或连接建立,也没有确认或否定确认。如果帧因冲突或校验错误被丢弃,将由更高层(如TCP)处理重传。以太网的MAC协议就是我们之前视频中描述的带二进制指数退避的CSMA/CD


以太网标准

随着时间的推移,出现了许多不同的以太网标准。以太网标准不仅涵盖帧结构和协议,还包括所支持物理接口的参数。

以太网支持多种速度和物理介质:

  • 速度:从10 Mbps、100 Mbps(快速以太网)、1 Gbps、10 Gbps到如今的400 Gbps。
  • 介质:包括早期的同轴电缆、如今常见的RJ45接口(四对双绞铜线),以及单模或多模光纤。

标准通常通过速度和介质来区分,例如 100BASE-TX(双绞线)、100BASE-FX(光纤)等。


本节课中我们一起学习了局域网链路层的核心组件。我们探讨了MAC地址的结构和特性,了解了ARP协议如何将IP地址解析为MAC地址以实现本地通信,并深入研究了以太网技术,包括其发展历史、帧结构和工作原理。理解这些概念是掌握数据在本地网络如何封装、寻址和传输的基础。

在下一个视频中,我们将继续讨论第2层交换机以及虚拟局域网(VLAN)。

6.6:以太网交换机与VLAN 🧠

在本节课中,我们将学习网络链路层中的两个核心设备:以太网交换机和虚拟局域网。我们将了解交换机如何通过自学习机制转发数据帧,以及VLAN如何通过逻辑划分来提升网络管理的灵活性与效率。


交换机基础 🔌

上一节我们介绍了共享介质以太网。本节中我们来看看一种更高效的设备:以太网交换机。

交换机是一种工作在链路层(第二层)的设备,它根据以太网帧的目的地址,主动执行存储和转发操作。在网络核心,你可能会遇到其他二层协议的交换机,但由于以太网最为常见,我们将专注于以太网交换机。

其基本操作是:交换机查看帧的目的地址,并决定应将帧转发到哪个端口。在访问链路时,它将使用以太网协议中的CSMA/CD算法。交换机的操作对主机是透明的,主机感觉不到交换机的存在,就像它们之间是直接连接的一样。由于其自学习行为,交换机的基本功能无需配置,可以即插即用。

以下是交换机网络的一个示例:

交换机的工作原理 ⚙️

现在,让我们深入了解交换机内部是如何工作的。

这里有一个包含交换机的以太网局域网。交换机有六个端口,每个主机独占一个端口。与我们之前讨论的共享介质架构不同,这里的每条链路都是一个独立的冲突域。由于每条链路上只有两个接口,它们可以运行全双工模式。交换机的每个端口都独立地运行以太网协议。

交换机还执行缓冲功能。就像我们在路由交换平面中看到的那样,如果出站端口存在争用,数据包可以被暂时缓冲,待端口可用时再传输。同样,也可能出现缓冲区溢出并丢包的拥塞情况。

综合来看,这意味着我们可以有多个数据流同时通过交换机。例如,A向A‘传输的同时,B可以向B’传输,这些流之间没有争用,可以同时进行,并各自利用其全部链路带宽。当然,如果两个不同的主机向同一个主机(例如A和C都向A‘)发送数据,它们将不得不共享交换机与A‘之间链路的带宽,交换机会暂时缓冲数据包并交错传输。但如果总速率超过A‘链路的带宽,缓冲区将开始丢包。

交换机的自学习过程 🧠

我们已经说过,交换机执行其基本功能无需任何配置。那么,它是如何知道将发往A‘的帧从正确的接口转发出去的呢?

交换机使用帧中的目的MAC地址。它必须以某种方式学习到,目的地址为A‘ MAC地址的帧需要从端口4转发出去。这正是存储在交换机转发表中的信息:MAC地址、关联端口和超时时间

回想三层路由器,我们必须手动或使用动态路由协议来配置路由表。那么,二层交换机是如何在没有配置步骤的情况下执行相同的转发功能的呢?

在交换机的情况下,它没有路由协议,也无需与其他交换机通信。相反,它能够学习到哪些主机可以通过哪个接口到达。过程如下:

假设主机A向A‘发送一个帧,此时交换机刚刚启动,其转发表为空。然而,每当交换机收到一个帧时,它都可以读取源地址,并刚刚学习到可以通过哪个接口到达该源地址。因此,从这个传入的帧中,它刚刚学习到A在接口1上。虽然这个信息对于下次需要向A发送帧时很有用,但它无助于交换机将帧送达A‘。

让我们看看当帧到达交换机时还会发生什么。

帧处理与转发决策 🔄

正如我们所见,交换机记录源MAC地址和帧到达的端口,以填充其转发表。MAC地址被用作该表的键或索引。正如我们之前提到的,MAC地址与其在网络中的位置之间没有结构关系,因此搜索此交换表需要精确匹配。

如果它在转发表中找到了帧中目的MAC地址的条目,那么它必须检查并确认是否在同一个接口上收到了此帧。这意味着它不会将帧从刚刚进入的同一端口发送回去。只要表中的端口与帧进入的端口不同,它就会根据交换表转发以太网帧。

但是,如果目的MAC地址尚未在转发表中呢?在这种情况下,交换机会将其从所有接口发送出去(泛洪)。在这里,你可以看到其行为与三层转发过程截然不同。在三层,默认行为是丢弃没有匹配转发记录的包,原因是可扩展性。交换机用于每个子网内主机数量相对较少的本地子网,因此它们可以偶尔承受将数据包泛洪到整个网络,以促进学习MAC地址的过程。而路由器则不能默认采用这种行为,因为如果这样做,它们最终会将发往未知目的地的数据包转发到整个互联网。

自学习示例 📝

让我们完成我们的示例。A向A‘发送一个帧,目前交换机的转发表中没有任何条目。

当帧到达交换机时,它从帧的源地址字段学习,并在转发表中填充A的MAC地址和端口号。由于A‘不在转发表中,它必须回退到默认行为,将帧泛洪到所有其他接口。

由于帧从所有端口发出,A‘收到了它并可以回复。A‘通过交换机向A发送一个帧,而交换机已经知道A在哪个接口上,因此它可以有选择地从该端口发送出去。同时,它也刚刚学习到A‘在哪个接口上,因此可以相应地填充其交换表。

现在,未来任何从A发往A‘的帧都只需要从通往A‘的端口发送出去,不再需要泛洪。

这就是交换机无需配置目的地就能填充其转发表的基本原理。即使多个交换机连接在一起,相同的行为也有效。现在我们有一台交换机连接了三台主机,并连接到多台其他交换机。这是常见的企业场景,例如,一个交换机连接走廊上的所有办公室,而所有走廊交换机都连接回一个楼宇交换机。如果我们需要将帧从A发送到G,其工作方式完全相同。A将向S1发送帧,如果S1不知道G的MAC地址在哪个接口上,它会将该帧泛洪给所有主机。现在,被泛洪的帧将到达S4,S4将执行相同的行为。因此,如果所有主机的表中都没有G的MAC地址,A的帧将到达整个网络上的每一台主机。

我们当然不希望泛洪过程发生得太频繁,因为它确实会消耗网络上每条链路的资源。然而,一旦G收到A的帧并回复,路径上的每台交换机都将学习到使用哪个接口可以到达G,针对G的MAC地址的泛洪就会停止。

交换机与路由器的对比 🌉

现在让我们将其与更大的图景联系起来。我们有一些交换机连接在一起,它们可以使用自学习到达该二层网络上的所有其他主机。由于所有这些交换机都挂在路由器的一个端口上,它们必须属于同一个IP子网。因此,自学习过程在到达路由器时停止。

与交换机不同,路由器只接受目的地址字段为路由器MAC地址的以太网帧。路由器不会转发目的地址为其他地址的以太网帧。因此,这种泛洪自学习发现过程的范围被限制在单个IP子网内。

作为提醒,让我们看看这些设备上的网络协议栈。我们的终端主机运行整个网络协议栈。然后我们有作为三层设备的路由器。当数据包到达路由器时,第一个二层报头被剥离,路由器只转发IP数据报,然后在输出端口创建一个全新的二层帧。然而,当该帧到达交换机时,交换机不会移除二层报头,它只是基于现有的二层目的地址做出转发决策。

因此,这两种设备都执行转发,我们甚至讨论过路由器内部的交换结构。所以真正的区别在于转发决策的标准。路由器使用路由算法基于IP地址计算转发表。而交换机学习二层MAC地址,并基于这些地址填充其交换表。

引入虚拟局域网 🏷️

现在我们将看看VLAN,这是一种增强功能,它修改了交换机的工作方式以增加灵活性。

我们提到了交换机MAC地址学习过程中的泛洪方面,这显然是一个可扩展性问题。任何时候你将一个数据包泛洪到整个网络,都是对资源的指数级消耗。我们也看到其他一些使用广播流量的协议。因此,任何使用目的广播地址的数据包也会被泛洪到整个交换以太网子网。

解决这个问题的一个方法是将子网拆分成多个更小的子网。这通过减少会听到每个泛洪帧的主机数量来提高效率。然而,如果每次用户移动并需要连接回特定交换机(因为它被路由器分隔开)时都必须更改物理布线,这可能会降低灵活性。在这个例子中,我们有一个计算机科学用户,其办公室物理位置在电子工程部门,但希望连接到计算机科学交换机。

在这种环境中,维护一个像我们在这张图片中看到的扁平交换局域网更容易,而不必担心用户在该网络拓扑中的物理位置。因此,我们有两个相互竞争的目标。我们为了效率而希望分割广播域,但为了方便而希望有一个大型扁平网络。

VLAN的解决方案 🧩

VLAN是解决这个问题的方案。我们可以将一台物理交换机划分为多台逻辑交换机。

例如,如果我们有一个用于走廊的交换机,但该走廊中的用户属于两个不同的逻辑组,我们并不真的希望必须添加一台单独的物理交换机,并从路由器到该交换机以及从该交换机到某些办公室铺设相关线缆。相反,我们在现有交换机上进行软件配置更改,就能够以这种方式划分用户。因此,该交换机将像两台或更多台物理交换机一样运行。如果需要,我们可以配置大量VLAN。

我们在如何实现这一点上也有一些灵活性。我们可以将物理端口分配给VLAN。

或者,我们可以将某些MAC地址分配给某些VLAN。因此,无论那台特定的计算机插入哪个端口,它将始终位于其配置所在的VLAN上。正如我们提到的,将其分成两个逻辑交换机的目的是通过减少听到广播或泛洪消息的主机数量来提高效率。这意味着这两个VLAN需要位于由路由器分隔的不同子网上。因此,每个VLAN都需要一个上行链路回到其VLAN内的其他交换机或路由器接口。

VLAN中继与802.1Q帧 🌉

通常,VLAN会跨越多个交换机。因此,在最简单的情况下,要连接这些交换机,我们需要一条连接红色VLAN的链路和一条单独连接蓝色VLAN的链路。

但这会导致其自身的可扩展性问题,需要在这些设备之间并行铺设多条电缆,并额外消耗交换机端口。因此,VLAN包含了中继端口的概念。来自多个VLAN的帧可以通过中继端口发送,并且它们有一个额外的报头字段,告诉接收方它们属于哪个VLAN。这个VLAN报头不是原始以太网规范的一部分,因此它在802.1Q标准中添加。

一个802.1Q帧在我们原始的以太网帧的“类型”字段之前添加了几个字段。这些字段包括标签协议标识符、VLAN ID本身(它有12位,因此如果需要,我们可以定义许多不同的VLAN)和一个3位的优先级字段。

总结 📚

本节课中我们一起学习了以太网交换机和虚拟局域网。

我们首先了解了交换机作为二层设备,如何通过自学习机制构建转发表,并基于MAC地址进行高效的、无需配置的帧转发。交换机将网络划分为多个独立的冲突域,支持全双工通信和并发数据流。

接着,我们探讨了VLAN技术。VLAN通过在物理交换机上创建逻辑交换机,解决了大型扁平网络广播效率低与网络管理灵活性需求之间的矛盾。它允许基于端口或MAC地址进行逻辑分组,并使用802.1Q帧格式和中继端口来实现跨交换机的VLAN通信。

总而言之,交换机是构建本地网络的基础,而VLAN则是在此基础上提供逻辑隔离和管理灵活性的强大工具。它们共同构成了现代企业网络架构的核心组成部分。

我们的下一个主题是MPLS(多协议标签交换),这是一种虚拟化链路的机制。

6.7:多协议标签交换 (MPLS) 🏷️

在本节课中,我们将要学习多协议标签交换(MPLS)。这是一种在数据链路层(第2层)和网络层(第3层)之间工作的技术,用于高效地转发数据包。我们将了解它的工作原理、优势以及与IP转发的区别。

什么是MPLS?🤔

MPLS,全称多协议标签交换,有时被称为“第2.5层”。这是因为它在第2层(如以太网)的头部和第3层(IP)的头部之间,插入了一个额外的“垫片”头部。

这个垫片头部包含一个固定长度的标识符,即标签。网络中的路由器根据这个标签,沿着预先配置好的路径转发数据包,而无需在每一跳都进行IP地址的最长前缀匹配查找。

MPLS的工作原理 ⚙️

上一节我们介绍了MPLS的基本概念,本节中我们来看看它的具体工作方式。

MPLS在数据包中插入一个头部,其结构可以简化为:

| 第2层头部 | MPLS头部 | IP头部 | 数据 |

MPLS头部包含标签值和其他几个字段,例如一个用于MPLS层的TTL字段。这意味着,当数据包在MPLS网络中传输时,IP头部的TTL字段不会被修改。

因此,可以将MPLS路径视为一个隧道。IP数据包从一端进入,从另一端原封不动地出来。中间的MPLS路由器(也称为标签交换路由器)不会处理IP头部,因此在traceroute等工具中可能不会显示。

MPLS路由器只查看标签值来决定将数据包发送到哪里。它们不查看IP头部,也不使用IP路由和转发表。

MPLS的决策与优势 🚀

MPLS决定为特定数据包分配哪个标签时,其原则与我们之前讨论的广义转发类似。它可以查看数据包的任何头部字段(如源IP、目的IP、端口号等),来决定数据包应该被放置到哪条MPLS路径上。

以下是MPLS带来的主要优势:

  • 流量工程:网络管理员可以灵活地引导流量走不同的路径,以优化网络性能或避免拥塞。
  • 服务质量:可以为不同的数据流分配优先级。
  • 快速故障恢复:可以预先计算好备份路径。当主路径出现故障时,流量可以非常快速地切换到备份路径上。

MPLS与IP转发的对比 🔄

为了更清楚地理解MPLS,我们将其与传统的IP转发进行对比。

假设有蓝色和绿色两个IP数据流,它们的目的地都是A。在基于目的地的IP转发中,这两个流会在网络中汇聚到同一条路径上。

而在MPLS网络中,数据流进入MPLS网络的第一个路由器(称为入口路由器)可以基于源地址等信息(而不仅仅是目的地址)来决定为每个流分配不同的标签。这样,出于流量工程的目的,这两个流就可以被引导至网络中不同的路径上。

虽然我们在课程后面才讨论MPLS,但它实际上比我们之前视频中讨论的SDN广义转发技术早了大约十年。然而,它与广义转发或软件定义网络有许多共同的目标。

MPLS的路径建立 🛠️

MPLS需要一些信令协议来建立预先计算好的路径。它通过修改后的链路状态路由协议(如OSPF-TE)来实现这一点。

值得注意的是,MPLS具有类似于虚电路网络的预留带宽概念。这使得在MPLS网络内部防止拥塞成为可能。

当建立一条MPLS路径时,路由器使用RSVP-TE协议通知网络中的其他路由器:它将使用哪个标签,以及带有该标签的数据包应该从哪个接口转发出去。

MPLS转发表示例 📋

让我们通过一个具体的例子来看MPLS的转发过程。

假设我们有一条从R4到R1的路径。以下是实现该路径的转发表:

  • R4 (入口路由器):接收到的数据包没有标签。R4根据其IP源和目的地址为其应用标签(例如标签10),然后根据MPLS转发表将其从接口0转发出去。
  • R3 (中转路由器):当带有标签10的数据包到达R3时,R3将其标签交换为标签6,并从接口1转发出去。
  • R1 (出口路由器):当带有标签6的数据包到达R1(MPLS网络的出口)时,R1移除MPLS标签,并将其作为普通IP数据包从接口0转发出去。

在这个过程中,标签会在每一跳被交换,直到在出口路由器被移除。

总结 📝

本节课中我们一起学习了多协议标签交换(MPLS)。我们了解到MPLS是一种“第2.5层”技术,它通过在数据包中添加标签,使路由器能够沿着预先配置的路径进行高效转发,而无需进行复杂的IP路由查找。MPLS支持灵活的流量工程、服务质量保证和快速的故障恢复。虽然它的路径建立需要额外的信令协议,但它为大规模网络管理提供了强大的控制能力。

在下一个视频中,我们将探讨数据中心网络的构建细节及其因巨大规模而必须考虑的特定因素。

6.8:数据中心网络 🏢

在本节课程中,我们将学习数据中心网络。数据中心是大型云服务、内容提供商和社交网络的核心基础设施,其网络设计面临着独特的挑战。我们将探讨其架构、设计目标以及相关的网络技术。

数据中心概述

上一节我们介绍了以太网和链路层交换,本节中我们来看看大规模网络——数据中心网络。数据中心通常容纳成千上万的服务器,这些服务器被尽可能紧凑地安置并通过网络连接。它们被主要的云提供商、内容提供商、社交网络和电子商务平台所使用。高性能计算中心和其他有大量计算需求的场所也会使用数据中心。

我们单独讨论数据中心网络,并非因为其技术截然不同,而是因为在这种规模下运营会面临独特的挑战。一个数据中心可能服务于特定企业,但该企业几乎肯定会在数据中心内运行多个应用程序,每个应用程序都服务于海量客户端。此外,在这种使用商用硬件的规模下,故障是常态,因此架构设计必须确保即使某些组件失效,系统也能继续正常运行。整个系统必须经过设计以避免瓶颈,无论是数据处理瓶颈、网络拥塞瓶颈、延迟瓶颈,甚至是电力和冷却资源的可用性瓶颈。

数据中心网络架构

接下来,我们具体看看数据中心的网络架构。通常,数据中心内摆满了服务器机架,一个典型的机架可容纳约40台服务器。每个机架顶部会有一个交换机,为这些服务器提供网络连接。为了冗余,通常还会配备两个顶架交换机,每台服务器都连接到这两个交换机上。

多个机架随后被聚合在一起,连接到第二层交换机。由于我们需要聚合来自多个机架的数据,第二层交换机与顶架交换机之间的链路带宽,通常高于顶架交换机与单个服务器之间的链路带宽。

在整个数据中心内,许多这样的机架集群通过第二层交换机聚合。第二层交换机再连接到第一层交换机。这种互连的目的不再是进一步聚合,而是提供一个灵活的交换主干网,使得任意两个机架之间,或任意机架与特定边界路由器之间,存在多条路径。

这种架构会根据访问应用程序的客户端位于数据中心内部还是外部而有所不同。对于典型的面向客户的应用程序,客户端位于数据中心外部,并通过这些边界路由器提供服务。

实例:Facebook的网络架构

Facebook是这种数据中心交换网络架构的一个具体例子。从概念上讲,他们的每个顶架交换机都连接到许多不同的结构交换机,而这些结构交换机又互连到许多不同的主干交换机。

回到我们简化的架构图,我们可以看到这种设计如何在网络中的任意两点之间提供多条不相交的路径。这既允许我们聚合这些路径的带宽以提高吞吐量,也允许我们在特定端口或交换机发生故障时,网络能够容忍故障。

在我们最近关于以太网的讨论中,没有谈到如果一个特定的MAC地址可以通过交换机的两个不同接口到达会发生什么。事实上,以太网交换机的基本自学习行为无法处理这种情况,如果发生这种情况,会导致环路并引发广播风暴。

因此,这种架构不能仅基于自学习的以太网交换机来部署,而是需要一个专用的控制器来配置通过这些网络的路径。这很可能使用我们在讨论OpenFlow时看到的某种软件定义网络变体。

应用负载均衡与性能要求

在这个例子中,我们还有一个专用的应用负载均衡器,它是面向客户端的服务器,负责处理传入的请求并将其分配给数据中心内的服务器。请求进入后,被发送到一个或一组服务器进行应答。这些服务器之间可能会相互通信,但应答会返回给应用负载均衡器,然后由它发送给客户端。

当我们谈论客户端请求时,可能指的是加载网页这样的操作。例如,当你在搜索引擎中输入查询并按下回车键时,请求会发送到这个应用负载均衡器,它必须与一堆服务器通信并获取答案,然后网页才能加载。因此,所有这些操作完成的时间预算通常只有几十毫秒。这就是为什么任何拥塞或延迟方面的瓶颈都会显著降低此类应用程序的性能。

数据中心驱动的协议创新

由于数据中心网络的需求,我们已经看到了许多协议创新。这些创新包括远程直接内存访问,即通过以太网实现的直接内存访问。我们讨论过的其他创新还包括显式拥塞通知。虽然ECN在公共互联网上难以使用,但在数据中心网络内部被广泛采用。请记住,ECN允许我们在不丢弃数据包的情况下管理拥塞,这对于我们试图最小化延迟时非常重要。

此外,还进行了逐跳拥塞控制的实验,因为它可以比等待TCP拥塞控制所需的端到端信令发生快得多。总的来说,我们看到软件定义网络在数据中心类型的网络中被采纳得最为迅速。在管理方面也有很多创新,以确定如何最佳地调度应用程序,或如何以最小化资源间网络延迟的方式将任务分配给可用的计算资源。

总结

本节课中,我们一起学习了数据中心网络。我们了解了数据中心的基本构成、其多层交换架构的设计目标(如冗余、避免瓶颈、提供多路径),以及Facebook的具体案例。我们还探讨了为何传统以太网的自学习机制不适用于这种复杂架构,从而需要软件定义网络等集中控制方式。最后,我们看到了数据中心对低延迟、高吞吐量的严苛要求如何推动了如RDMA、ECN等网络协议的创新。数据中心网络是现代互联网服务的基石,其设计深刻体现了在超大规模下对可靠性、效率和性能的极致追求。

在下一个视频中,我们将通过“一个Web请求的一天”,来串联我们迄今为止所学的所有网络层次,看看从客户端请求网页到收到响应并显示页面,中间必须发生的所有步骤。

6.9:一个Web请求的生命周期回顾 🕸️

在本节课中,我们将整合之前学到的所有网络知识,完整地走一遍从连接到网络、发起请求到加载网页的全过程。我们将看到应用层、传输层、网络层和链路层是如何协同工作的。

场景设定与网络架构

上一节我们介绍了课程的目标,本节中我们来看看具体的场景。我们的场景是:一名学生带着笔记本电脑连接到校园网,然后访问一个搜索引擎。

互联网是网络的网络。因此,我们有校园网连接到互联网服务提供商(ISP),而ISP又连接到谷歌的网络。笔记本电脑到达并连接到校园网,请求一个网页,然后就能显示搜索引擎的主页。但这过程并不简单。

第一步:获取IP地址(DHCP)

我们知道,在浏览器能连接任何东西之前,设备需要在其刚连接到的网络上获得一个地址。像大多数校园网一样,它将使用动态主机配置协议(DHCP)来获取地址。

以下是DHCP请求的封装过程:

  1. DHCP客户端是一个运行在UDP之上的应用程序,因此请求将被封装在UDP数据报中。
  2. 然后UDP数据报被封装在IP数据报中。
  3. 最后,IP数据报被封装在一个以太网帧中,以便在网络中转发。

客户端不知道DHCP服务器在哪里,因此它会广播这个请求。当请求到达服务器时,该帧将被解封装到IP层,再到UDP层,最后到达DHCP服务器应用程序。

接着,服务器将创建DHCP确认报文,将其重新封装并通过所有层,再次广播到网络中,最终返回给客户端的DHCP应用程序。为了接受这个地址,客户端会发送另一个针对该特定地址的请求,并由服务器确认。这个交换过程包含四个部分。

此时,客户端将拥有其IP地址,同时还会获得一些DNS服务器的地址、网关路由器的地址,以及本地网络的其他一些详细信息。

第二步:解析域名(DNS与ARP)

但我们仍然没有准备好发送应用层请求,因为我们不知道要将请求发送到哪个IP地址。因此,我们需要准备发送DNS请求。

DNS也是一个运行在UDP/IP/以太网等协议之上的应用程序。该请求将被封装并到达链路层。由于DNS服务器不在本地子网上,该请求需要通过网关路由器发送。

虽然主机知道需要将此请求发送给网关路由器,但它没有网关路由器的MAC地址。因此,在继续之前,我们必须使用地址解析协议(ARP)。

我们的ARP查询会在网络中广播:“谁有这个IP地址?”当网关路由器收到它时,它将用自己的MAC地址进行回复。

此时,我们就有了必要的ARP表项,可以将承载DNS请求的帧发送给网关路由器。

在这个案例中,DNS服务由ISP运行。因此,我们的UDP数据包到达网关路由器后,就可以被转发到ISP的网络,并通过其网络到达DNS服务器。

但要记住,为了让这一切正常工作,ISP的内部域内路由协议必须正常运行,以便将转发表分发给路由器。同时,校园网和ISP之间的边界网关协议(BGP)也必须正常工作。

现在,我们的帧已经到达DNS服务器,它被解封装并通过协议栈到达运行在UDP之上的DNS应用程序。这将是一个递归解析器。在本例中,它看起来已经缓存了谷歌的IP地址。

但如果它没有缓存,则必须通过DNS层次结构向外查询,依次查询根服务器、顶级域(TLD)服务器,最后是谷歌的权威名称服务器,以获取该IP地址并将其发送回请求客户端。

第三步:建立TCP连接与HTTP请求

现在客户端知道了要将请求发送到哪个IP地址,我们终于可以进行HTTP协议本身的操作了。在这里,创建了GET请求。

但在封装之前,我们必须执行TCP连接。因此,TCP创建一个控制报文(SYN),将其封装并通过协议栈向下传递,完成三次握手的第一个部分。

当SYN报文到达服务器的传输层时,TCP会响应一个SYN-ACK报文,并通过网络发送回客户端。一旦客户端TCP确认了SYN-ACK,连接就完全建立。通常,TCP会在这个ACK报文中捎带初始数据,因此GET请求可以在这个时候发送出去。

现在,我们终于可以看看HTTP层了。我们看到GET请求被封装在TCP之上并发送出去。请记住,TCP在整个过程中将采用慢启动和拥塞控制机制。

该消息被发送到服务器,服务器将其解封装到Web服务器应用程序。服务器可以用回复进行响应,如果请求有效,回复中将包含请求的网页。

然后,当数据包返回到客户端并被解封装到应用程序时,它就可以开始显示网页了。当然,这个初始对象只是基础的HTML,HTML中引用的任何样式、图形或其他资源都需要通过额外的连接来获取。

总结与本章回顾

尽管这个“Web请求的生命周期”过程如此复杂,我们仍然不得不简化了沿途的许多步骤。但希望这有助于将我们在课程中迄今为止所学的所有网络层次联系起来。

完成这个案例后,我们简要回顾一下第6章链路层的内容。

回到本章开头,我们看到链路层比网络的其他层更关注差错检测和纠正,因为它最接近实际发生比特翻转的物理层。

链路层的另一个主要职责是管理对共享信道的访问,即多路访问控制。作为其中的一部分,我们有了链路层地址(如MAC地址),以便帧能够到达其指定的接收者。

我们研究了以太网实现的具体细节,以及交换式以太网局域网和在其之上扩展的虚拟局域网(VLAN)的构建。

然后在上一个视频中,我们研究了多协议标签交换(MPLS)协议,它使我们能够创建虚拟化的链路或电路。最后,我们通过观察一个Web请求的生命周期来总结,将迄今为止所学的所有网络层次联系在一起。

就本课程而言,这完成了我们在协议栈自上而下的旅程。在每一层,我们都研究了该层所提供服务背后的原理以及它们在实践中的实现方式。

但这并不意味着我们已经完成了。在后续章节中,我们还有几个跨领域主题需要探讨。第一个是无线网络,我们将在第7章中学习;最后一个是网络安全,我们将在第8章中学习。

这结束了我们对Jim Kurose《自顶向下的方法》第6章的讨论。在下一个视频中,我们将开始第7章的学习。

7.1:无线与移动网络挑战 🛰️

在本章中,我们将开始学习无线网络特有的挑战以及用于应对这些挑战的技术。我们将从无线网络的基本元素入手,探讨无线链路与有线链路的区别,并介绍一些关键的无线通信概念。


无线网络概述 📡

我们已完成前六章的学习,从应用层一路向下深入到了链路层。现在,我们将开始关注无线环境特有的方法。

当前,移动电话用户数量是有线电话用户的十倍,移动无线互联网连接设备数量是固定宽带用户的五倍。此外,在4G和5G网络中,网络核心已从基于电路的结构转向基于IP的结构。向无线设备的转变显然由需求和便利性驱动,但也带来了一些高层挑战,这些挑战在网络协议栈中转化为众多技术难题。其中一个高层挑战是无线信道的特性,仅仅维持无线链路上的通信就比维持有线链路通信困难得多。无线的“无束缚”特性也带来了移动性,但这又引入了一系列额外的挑战。请记住,IP协议栈最初是专为有线网络设计的,因此这些无线和移动挑战完全超出了IP网络服务最初设计的范畴。

在本视频中,我们将介绍无线网络、相关挑战以及无线链路的一些特性。本章后续部分,我们将探讨基于802.11的网络以及蜂窝网络。我们还将研究围绕移动性的问题以及用于支持移动性的一些特定技术。


无线网络元素 🔗

首先,让我们概览无线网络的一些基本元素。通常,无线网络是有线网络的延伸,无线链路是接入网络的一部分,但网络核心仍然是我们迄今为止讨论的互联网有线核心。

在无线领域中,我们有无线主机,例如笔记本电脑、智能手机和物联网设备,这些设备运行着产生流量的应用程序。需要指出,并非所有无线设备都是移动的。有时,为特定设备连接有线线路过于困难或昂贵,因此即使该设备不需要移动,它仍将通过无线网络连接。

除了无线主机,我们还有无线基础设施,通常称为基站或接入点。这些可以是家庭中的无线局域网接入点,也可以是安装在蜂窝塔上的基站。我们通常认为基站是固定的,并覆盖特定的地理区域。在大多数情况下,基站有一个有线回程链路将其连接到互联网。当然也有例外,例如基站可能安装在车辆上,或者基站的回程链路也可能是无线的。常见的例子包括已存在十年左右的无线热点,以及越来越多新车型中提供的接入点选项。

在我们的基站和无线主机之间,存在无线链路。这个第二层环境可以有不同的数据速率和操作范围,并可能使用一个或多个信道进行通信。无线多路访问控制协议协调所有无线主机和基站对链路的访问。


带宽与范围的权衡 ⚖️

我们通常看到带宽和范围之间的权衡。这通常是因为在较高频率载波上更容易创建高带宽链路,但频段越高,信号在传播过程中能量损失越快,因此较低频率更适合长距离链路。

此图表并非详尽无遗,因为微波和卫星无线链路技术的传播距离远超过这些。在此图中,我们仅关注无线局域网和无线蜂窝技术。目前大多数消费设备使用802.11ac协议,该协议向后兼容802.11n、g和b。我们也开始看到以Wi-Fi 6(即802.11ax的市场名称)为卖点的消费设备。还应注意,这里更快的速度依赖于将多个信道绑定在一起,因此许多设备不支持协议所支持的最高峰值速度。


基于基础设施的无线网络 🏗️

到目前为止,我们讨论的都是基于基础设施的无线网络,这意味着无线网络依赖固定基础设施(如基站、蜂窝塔和有线回程链路)来运行。无线节点不直接相互通信,它们只与基站通信。此外,还有切换机制,使得移动无线节点能够相对无缝地从一个基站过渡到另一个基站。


自组织无线网络 🔄

与此相反,我们有自组织无线网络,其中无线主机直接相互通信。它们必须自行组织成网络,并且只能在无线电范围内通信,没有基站来中继从一个节点到另一个节点的传输。然而,在基础设施不存在、受损或不可用的环境中,能够创建这样的网络无疑是有利的。因此,我们遇到的最常见的无线网络是基于基础设施的单跳网络。


无线网络类型总结 📊

以下是不同类型的无线网络:

  • 单跳、基于基础设施的网络:每个无线主机仅与一个基站通信,该基站有一个回程链路连接到互联网的其余部分。
  • 网状网络:在连接到互联网的设备之前,存在多个无线跳。例如,Wi-Fi中继器可能属于此类。
  • 无基础设施的单跳网络:例如蓝牙或Wi-Fi直连。
  • 多跳无线网络:没有基础设施,因此作为无线主机参与网络的设备也为相邻设备路由和转发数据包。此类网络通常称为移动自组织网络或车载自组织网络。

无线链路与有线链路的比较 📶

现在,让我们看看无线链路与有线链路的比较。一个重要区别是衰减对无线信号的影响。虽然有线信号确实会衰减,但其衰减速率远低于无线环境。此外,与在空气中传播相比,无线信号在穿过建筑物等固体物体时受到的影响要大得多。

此外,无线链路极易受到干扰。对于我们习惯处理的无线局域网,它们使用的频段与许多其他无线电设备以及可能在某些相同频率发射噪声的其他电子设备共享,还有同样工作在2.4 GHz并倾向于发射大量无线电噪声的微波炉。也很容易出现多个无线网络试图在同一时间在同一信道上运行并相互干扰的情况。

除了被物体衰减外,无线电波还会从物体上反射,这些反射会干扰原始信号。因此,在衰减和多径干扰之间,即使看似简单的无线链路也可能相当具有挑战性,并且容易导致数据包损坏。


信噪比与链路自适应 🔧

为了使无线链路有用,通常需要有一个阈值信噪比,链路必须在此之上运行,低于此值,接收器将无法正确解码数据包。因此,为了提高信噪比,我们需要以更高的功率传输或使用调谐更好的天线来接收信号。因此,随着传输功率的增加,信噪比增加,误码率降低。

然而,设备限制和法规限制了我们能够传输的功率。因此,如果我们被限制在给定的信噪比下,我们希望我们的链路层能够相应地适应,以便在当前信噪比下通过链路获得最多的可用数据。在此图表中,我们看到三种不同的编码,对应三种不同的数据速率。随着链路质量的下降,设备可以回退到较低的数据速率,即在给定信噪比下实现较低误码率的编码。


隐藏终端问题 🚫

我们在无线环境中遇到的另一个问题是隐藏终端问题。当我们运行某种分布式媒体访问控制算法时,并非所有节点都能听到彼此,因此如果我们试图使用像载波侦听这样的机制,它假设所有节点都能听到彼此,那么隐藏终端问题可能导致意外的冲突。

在此示例中,B可以听到A和C,但A和C听不到彼此。我们在这些网络中处理的大多数频率范围被认为是视距传输,这意味着它们被地面衰减得非常厉害,如果两个端点之间有山丘或土堆,则基本上没有传输。因此,画出A和C的信号衰减,我们可以看到它们到达B,但被中间的山脉大大衰减,因此它们无法到达彼此。这意味着如果A和C都侦听信道,并且一个开始传输,另一个不会听到,因此另一个可能同时开始传输,导致冲突,这意味着B将无法提取任何一方的通信。因此,我们可以使用额外的机制来处理这个问题,稍后我们会讨论这些机制。


码分多址访问 📡

回到链路层开始时,我们讨论了带宽共享机制,我们描述的是时分多址和频分多址。我们提到还有一种是码分多址访问,然而它不用于有线环境,因此我们将其保留到无线章节来讨论。在这种情况下,为每个用户分配一个唯一的代码。

因此,所有用户在同一频率上传输,这与频分多址不同,但在传输数据之前,他们必须使用分配的码片序列对其进行编码。这些码片序列彼此正交,因此编码仅包括将原始数据与码片序列进行内积运算,并且可以通过对编码数据和码片序列进行求和内积来解码。


CDMA 编码与解码示例 💻

在此示例中,我们将仅查看编码来自接收方的两个时隙的数据,然后在接收方解码。在这种情况下,每个时隙传输一个实际数据位,但我们看到在该时隙内有一个八位的码片序列。

由于此处传输的位是1,当进行内积运算时,我们看到输出就是码片序列。然后,在下一个时隙,我们传输一个零。因此,我们看到内积运算导致传输码片序列的反码。然后,信道输出到达接收器。它需要提取原始数据,并且它知道发送方的码片序列。因此,它能够对这两个传输进行求和内积运算并检索原始数据。这样,我们编码和解码了一个发送方到一个接收方。


多发送方 CDMA 示例 🔄

当有多个发送方时,这就变得有趣了。当然,我们说这是一种在多个用户之间划分可用带宽的机制。现在,我们有两个发送方。

这些发送方具有正交的码片序列。它们都编码两位数据,并且它们的时隙是对齐的。因此,在信道上广播的是这两个传输的干扰,也就是两个传输的总和。当接收器获得求和传输时,它能够选择应用哪个发送方的码片序列,并仅从该发送方检索原始数据。因此,即使我们有多个发送方在同一时隙同时传输,我们也能够以允许我们检索所有发送数据的方式建设性地利用干扰。

现在,我们注意到发送方必须使用码片序列将每个数据位编码为信道上的多个位。因此,这里没有免费的午餐,每个发送方只能获得可用带宽的一部分,因为在这种情况下,它们必须为每一位数据传输八位。


总结 📝

本节课我们一起学习了无线环境和无线链路的介绍。我们探讨了无线网络的基本元素、类型、无线链路与有线链路的区别、信噪比的重要性、隐藏终端问题以及码分多址访问的基本原理。在下一个视频中,我们将开始研究802.11无线局域网。

7.2:802.11 WiFi 如何工作 📶

在本节课中,我们将学习802.11协议,即我们通常所说的WiFi,是如何设计的。我们将探讨其网络架构、信道接入机制、帧格式以及一些关键特性,如移动性、速率适配和电源管理。


上一节我们讨论了无线链路与有线链路的区别及其带来的挑战。本节中,我们来看看无线链路层的一些具体设计决策。我们将从802.11无线局域网(WLAN)开始,它通常被称为WiFi或无线以太网。

以下是802.11协议家族的一些关键版本及其特性:

  • 802.11b:最早被消费者广泛部署的版本。
  • 802.11g:在几年后推出,显著提高了可用带宽。
  • 802.11ac:目前常见的部署版本。
  • 802.11ax:最新版本,在市场营销中常被称为WiFi 6
  • 802.11af/ah:设计用于更长距离通信的变体,但速度远低于同期开发的短距离版本。

所有这些协议都有一个共同点:它们都使用我们在前一章讨论过的CSMA/CA(载波侦听多路访问/冲突避免)算法。虽然我们通常认为它们运行在基础设施模式下(即存在指定的基站),但规范中也定义了自组织模式,允许设备在不使用基站的情况下直接通信。


了解了协议概览后,我们来看看WiFi网络的基本架构。在这些网络中,“基站”和“接入点”这两个术语可以互换使用。虽然我们通常不讨论无线局域网的“蜂窝”,但存在一个等效概念:BSS(基本服务集)。

BSS包括一个接入点和所有与该特定接入点通信的主机。一个主机可能同时处于多个接入点的覆盖范围内,它会选择或被指示应与哪个接入点通信。它们还具有在同一无线网络内从一个接入点漫游到另一个接入点的能力。


每个可用频段(2.4GHz和5GHz)都有多个信道。以下是接入点配置和主机关联的过程:

当接入点被配置时,配置的一部分是选择它应在该频段内的哪个信道上运行。如果两个在彼此覆盖范围内的接入点被配置在同一个信道上,它们会相互干扰。因此,仔细勘察无线环境并选择信道非常重要,以避免相邻接入点冲突。

当一个新的主机加入网络时,它会与一个特定的接入点进行关联过程。这个过程始于主机扫描可用信道,监听所有802.11接入点定期发送的信标帧。信标帧包含SSID(可能被多个接入点共享)和接入点的MAC地址(主机用来区分不同的接入点)。基于监听到的信标帧,主机可以选择要关联的接入点。802.11规范还包括各种形式的认证,可能在允许完成关联之前需要。关联完成后,主机就可以像在有线局域网中一样使用DHCP来获取子网上的IP地址。


让我们更详细地看看信道扫描过程。这始于新主机进入监听模式并轮询各个信道。一旦主机识别出来自某个网络的信标帧,它就可以发送关联请求并接收关联响应。

这个过程的第一步可能花费一些时间,因为当主机在一个信道上监听信标帧时,可能会错过附近接入点在其他信道上发送的信标帧。

对此有一种替代方案:主动扫描。在这种情况下,当主机开始在某个信道上监听时,它会发送一个探测请求,然后该信道上的任何接入点都会发送一个探测响应,其中包含与信标中相同的信息。关联过程与被动情况相同。

所有现代操作系统都使用主动扫描方法来加速与无线网络的关联。然而,需要注意的是,这里存在一个重大的安全漏洞:探测请求包含此主机过去连接过的SSID列表。恶意接入点可以窃听这个已知SSID列表,并发送探测响应,假装是其中一个SSID,以诱骗主机连接到这个恶意接入点。然后,恶意接入点就可以对该主机的流量执行中间人攻击。虽然有一些缓解措施,但这超出了本课程的范围。


正如我们已经多次提到的,802.11使用CSMA/CA算法。这意味着如果一个节点正在传输,那么所有其他节点都应该监听,而不是同时开始传输。同时,这种机制容易受到隐藏终端问题的影响:并非所有节点都能听到网络中其他每个节点的传输。

此外,这是CSMA/CA,而不是CD。在有线以太网中,我们有CSMA/CD(带冲突检测的载波侦听多路访问)。然而,在无线环境中,在冲突发生时检测它们在技术上非常具有挑战性,因此无线网络中没有冲突检测,取而代之的是冲突避免(CSMA/CA)。


那么,让我们看看它是如何工作的。首先,在开始传输之前,有一个指定的监听信道的时间,称为DIFS(分布式协调功能帧间间隔)。

如果在DIFS期间没有检测到其他传输,则完整地传输数据帧。请记住,在无线网络中我们无法感知冲突,因此发送方没有理由在传输完整帧之前停止。

相反,如果在DIFS期间信道已被占用,则发送方将等待并启动一个随机退避计时器,然后再次开始侦听。这类似于我们见过的其他随机退避过程,因为如果信道被占用,并且多个其他发送方正在侦听信道,它们会在传输停止后立即开始它们的DIFS期,那么它们都会感知到信道空闲,但会同时开始传输,导致冲突。因此,它们不是尽可能在信道空闲时立即传输,而是必须等待这个随机退避期,以便希望一次只有一个主机开始传输,而其他主机将感知到该传输并避免与之冲突。

在接收方,数据帧被接收并被确认,这个确认发生在SIFS(短帧间间隔)之后。这样,发送方就知道没有发生冲突。如果他们没有收到ACK,帧将必须重传。SIFS比DIFS短得多,因此如果有ACK要发送,它将在任何DIFS期到期之前发生,所以ACK将是帧成功接收后信道上下一个发送的数据包。

只要没有太多主机试图共享信道,这个CSMA/CA算法就能很好地工作。


然而,对于更拥挤的信道,我们可以采用一种称为RTS/CTS的额外机制。这里的想法是,信道首先由发送方发送一个请求发送(RTS)的小控制包来预留,然后基站广播出下一个允许使用信道的主机以及使用时长。因此,虽然隐藏终端问题意味着一些主机可能听不到其他主机的RTS传输,但根据定义,它们在基站的覆盖范围内,所以它们会听到基站发送的允许发送(CTS),从而知道不要传输,进而在发送方传输数据时避免冲突。RTS控制消息本身可能仍然会相互冲突,但它们很小,因此浪费的带宽最少。这样,在CTS到期(即源已发送其数据帧)后,其他主机将知道需要等待多长时间,然后如果需要发送数据,它们可以发送自己的RTS来预留信道。

现在让我们看看RTS/CTS交换过程。在这种情况下,主机A和B大约同时发送RTS,它们发生了冲突。这意味着基站无法解释这些传输,因此没有发出CTS。经过随机退避后,A首先用RTS重试,虽然我们显示这个RTS由于衰减没有到达B,但基站传输了CTS,所以B知道在指定时间内不要传输。因此它推迟了传输,而A获得了信道来传输其数据帧。当该帧到达接入点时,它发送确认,因此A知道没有发生冲突,并且传输被正确接收。


现在我们可以看看802.11的帧格式。相对于我们看过的其他头部,802.11帧最值得注意的一点是它有四个地址字段

这允许我们包含有线链路上的地址,以及可能在同一IP子网的有线段上重要的地址。请记住,我们的第二层MAC地址在整个广播域中都有意义,而这些无线单跳链路可能是更大的以太网广播环境的一部分。

以下是地址字段的用途:

  • 地址1:此传输的目的地(无线主机或接入点)。
  • 地址2:此传输的发送方(无线主机或接入点)。
  • 地址3:子网网关地址。如果此帧最终需要到达有线网络上的路由器或其他主机,接入点将知道使用哪个MAC地址作为目的地并转发它。
  • 地址4:在自组织模式下使用,用于区分给定链路上的帧发送方和接收方,以及整个子网内的发送方和接收方。

让我们看一个编址的例子。假设H1向接入点发送一个帧。由于我们处于基础设施模式,我们只使用前三个地址。因此,此无线传输的目的地是接入点的MAC地址,发送方是H1的MAC地址。然而,在此子网内,目的地是路由器的网关地址,因此R1的MAC地址被用在第三个地址字段中。这样,当无线接入点需要构建有线以太网头部时,它就知道在目的字段中使用哪个MAC地址。


帧中还有其他重要字段:

  • 持续时间字段:用于RTS/CTS交换。
  • 序列号:用于将确认与传输匹配起来。
  • 帧控制字段(2字节):用于指定协议版本、链路上是否使用加密、是否是重传、是否分片、帧是发往接入点还是来自接入点,以及消息的类型和子类型(可以区分控制帧和数据帧,控制帧即我们刚讨论的RTS、CTS和ACK帧)。

我们还提到,移动性可以发生在接入点之间。因为这是在第二层环境中处理的,所以从IP的角度看是透明的。


假设有两个参与同一无线网络的基本服务集,主机H1正从一个接入点过渡到另一个接入点(可能是因为它移动到了离第二个接入点更近的地方,信号更强)。那么问题是:来自路由器的以太网帧如何到达正确的接入点?

答案是:这与我们之前在有线以太网交换机中看到的自学习过程相同。如果我将一台主机从一台交换机拔下并插入另一台交换机,所有交换机都会自学习该MAC地址现在位于何处。同样的事情发生在无线环境中:当H1的MAC地址从一个接入点移动到另一个接入点时,那些帧开始从新的接入点发出,交换机相应地更新其交换表。


我们还提到了在无线环境中速率适配的重要性。这是802.11协议中实现的一个功能。如果信噪比高,那么基站和主机将协商一个高编码速率,从而允许链路上有更高的带宽。然而,如果信噪比下降,它们也会相应地降低编码速率,以在降低的信噪比下工作。

在这个例子中,主机正在远离基站,导致误码率增加。随着误码率增加,这将导致802.11中重传增加,从而显著降低信道效率。因此,当误码率变得太高时,基站将切换到具有更低误码率的较低编码速率。


802.11的另一个重要特性是电源管理,因为许多无线设备也是电池供电的,而无线电可以消耗该设备总能量的很大一部分,这对电池寿命有显著影响。

基本上,无线节点能够让接入点知道它将关闭无线电直到下一个信标帧。因此,接入点在该特定节点的下一个信标帧之前,不会传输任何为其准备的帧。无线主机将唤醒并接收信标帧,在该信标帧中将有一个列表,列出所有在接入点有帧等待它们的无线设备。因此,如果此特定节点在该列表上,它将保持唤醒状态并等待接入点传输其帧。


覆盖比局域网更小地理区域的是个域网。其中最常见的是蓝牙。这些基本上是为了减少便利或舒适所需的电缆数量而设计的。

它们在某种意义上也是自组织的,因为没有专用的基站,但是每个蓝牙网络都有一个指定的控制器,其余设备以客户端模式运行。它们也共享2.4GHz频段,因此可能与802.11协议相互干扰。它们使用一种轮询方案,即控制器轮询客户端以查看它们是否有数据要发送。

为了应对干扰问题,采用了跳频方法。设备从一个信道跳到另一个信道,虽然它们可能会在某些时隙和信道上与其他传输冲突,但大多数时隙应该是无干扰的。此外,因为在大多数情况下我们谈论的是更小的电池供电设备,能量管理在这些环境中非常重要。蓝牙通过休眠模式来处理这个问题,因此客户端如果不在传输或接收,可以有效地进入睡眠状态。


本节课中,我们一起学习了802.11无线局域网(无线以太网)的工作原理,包括其协议家族、网络架构、CSMA/CA接入机制、RTS/CTS、帧格式、移动性、速率适配和电源管理等关键概念。在下一个视频中,我们将继续探讨蜂窝网络环境,它与无线局域网有许多共同特征,但也有一些显著差异。

7.3:蜂窝4G与5G网络工作原理 📡

在本节课中,我们将学习蜂窝4G和5G网络的工作原理。我们将探讨其架构、核心组件、协议栈以及它们与之前学习的Wi-Fi网络的主要区别。


欢迎回到第7章。在本视频中,我们将探讨蜂窝数据网络。这些网络与我们上一节学习的Wi-Fi网络有许多相似之处,但也存在显著差异。

正如我们所知,蜂窝网络是目前移动互联网服务的主导解决方案,其设备数量是固定宽带设备的5倍。虽然我们都曾遇到过信号盲区,但在绝大多数人口密集区域,蜂窝宽带服务已经覆盖。相关技术能够提供数百兆比特每秒的带宽,尽管实际观察到的带宽会因多种因素而异。与我们之前学习的互联网协议一样,移动网络协议也由一系列标准所规范。


蜂窝网络架构概览

在蜂窝网络中,我们可以观察到与整个互联网相似的结构。一个特定的运营商将拥有一个核心网络和一个接入网络,它们共同构成了移动蜂窝网络。除此之外,它还连接到互联网的核心。许多不同的蜂窝网络组成了一个“网络的网络”,其客户可以使用语音和数据服务进行通信。运行在IP协议栈上的互联网数据服务在移动网络中已无处不在。我们可以将移动网络视为一个接入网络,它将用户连接到有线互联网。

移动无线网络的主要区别在于第二层(数据链路层),这与802.11标准有显著不同。部分原因是为了实现比无线局域网(WLAN)预期更高的移动性。此外,计费概念更强,需要跟踪设备身份以便向正确的用户收费。由于涉及金钱,还需要身份验证以防止未经授权的账户使用。


网络组件与术语

让我们从架构角度看看这是如何实现的。移动设备,在通用网络术语中称为主机,在移动网络中被称为用户设备UE。它们连接到基站(通常位于塔上)。UE可以是手持设备、笔记本电脑、嵌入车辆中的设备,甚至在某些情况下连接到建筑物等非移动设施。

这些设备被组织成小区,每个小区都有自己的基站。小区连接到分组核心网。分组核心网仍然是移动无线网络的一部分,因为它明确支持小区间的移动性,我们将在后续幻灯片中看到更多相关内容。

在4G之前,分组核心网分为独立的语音和数据服务。但随着LTE的出现,这些服务融合了,所有服务都通过核心网中的IP网络提供。UE通过其SIM卡上存储的号码进行识别,称为IMSI(国际移动用户识别码)。这个号码旨在全球范围内唯一,是一个64位数字。

每个基站管理自己的小区,并且每个基站也有一个标识符,UE可以借此区分来自不同基站的传输。所有设备都必须向基站进行身份验证,这要求基站与分组核心网中的元素进行交互。基站之间也会相互协调,以优化网络负载并促进用户从一个小区到另一个小区的移动。


归属网络与漫游

移动网络有很强的“归属网络”概念。因此,一个用户向一个提供商付费,但可能漫游到其他提供商的网络。在这种架构中,归属网络提供的服务与漫游网络不同。

归属网络为其自己的客户维护归属用户服务器HSS。这是将IMSI号码与用户身份(如姓名、账单地址等)关联起来的地方。它还会维护用户已订阅的活跃服务信息。

正如您可能预期的那样,分组核心网中也有一些路由器,其中一些具有特定功能。有一个通往互联网的网关,称为分组数据网络网关。我们注意到,这通常提供NAT服务。几乎所有移动网络都大量使用NAT,因为它们设备数量庞大,没有足够的IPv4地址为每个设备分配唯一的公网地址。

此外,还有服务网关,这是基站使用的分组核心网的入口点。


移动性管理

归属用户服务器管理相对静态的数据(可能由人工不时更新),而我们可以将移动性管理实体视为管理设备连接的实时状态。这包括支持设备身份验证、跟踪设备连接到哪个小区以进行呼叫路由,以及在设备从一个小区移动到另一个小区时协助切换。它还设置在设备和分组数据网络网关之间用于访问互联网的隧道。


控制平面与数据平面

正如互联网的其他部分一样,移动网络中也存在控制平面数据平面的区别。在这种情况下,数据平面大量使用隧道协议,而控制平面则负责移动性、安全和身份验证。由于我们有一个发送IP流量的设备,同时核心网也运行着IP网络,我们最终会使用IP-over-IP隧道


第二层协议栈

在这种环境下的第二层可以细分为几个组件,包括分组数据汇聚层无线链路控制层介质访问控制层

  • 分组数据汇聚层负责用户数据的压缩和加密等。
  • 无线链路控制层负责在用户设备和基站之间可靠地传输帧。
  • 介质访问控制层,正如我们之前所见,协商无线电传输时隙的使用。

虽然用户设备和基站之间有一个单跳无线接入网络,这与我们的802.11协议直接类似,但在这个环境中,我们同时执行频分复用时分复用功能,这意味着这些无线电在技术上比802.11无线电更先进。

在共享无线信道内,每个设备被分配两个或多个半毫秒时隙,分布在12个频率上。因此,无线电不断在频率之间跳变,以在这些半毫秒时隙上发送数据。如果您还记得我们之前看到的调度算法,最简单的当然是先进先出,但在实践中,运营商可能会区分服务类别,并优先处理某些类型的数据。


隧道协议与移动性

在网络的分组核心网一侧,我们有启用隧道所需的协议栈。因此,虽然我们的链路技术将是运行IP的传统有线链路,但我们还会看到一个UDP层和一个隧道协议层。因此,我们从用户设备获得的任何数据(例如,一个HTTP over TCP over IP的数据包)现在将被封装在这个隧道协议内部。

隧道随后到达服务网关。服务网关将其解封装,但将其放入一个新的隧道中以到达分组数据网络网关。这种隧道架构的好处是,用户设备在移动时可以保留其IP地址,因为隧道内部的子网独立于隧道所经过的子网。


与基站关联的过程

现在让我们看看与基站关联的过程。我们的用户设备出现时,可能会听到来自多个基站的无线电数据包,并请求与信号最强的那个关联。所有基站每5毫秒传输一次同步信号。如果您还记得,这个链路层的一部分是时分复用,这要求使用信道的所有设备的时钟之间紧密同步。

移动设备读取这个同步信号(包括来自多个基站的同步信号),并从中了解它应该使用的无线电配置,包括信道带宽、基站所属的运营商以及其他配置信息。最后一步,设备选择一个基站进行连接。虽然在其他条件相同的情况下,它更愿意连接到最强的信号,但它可能更愿意连接到归属运营商,即使来自不同运营商的信号更强。这是因为运营商通常在不需向第三方支付其用户数据传输费用时能赚取更多利润。

请注意,这只是与基站的关联。完全启用连接还需要身份验证以及通过网络核心建立数据平面。


电源管理

正如我们讨论Wi-Fi和蓝牙时提到的,电源管理是这些协议的重要组成部分。因此,移动设备也支持睡眠模式的概念。当处于轻度睡眠模式时,它大约每100毫秒唤醒一次,并与基站检查是否有需要接收的帧。但它也可以进入深度睡眠模式,在这种模式下,它一次可以很多秒不接受流量。


运营商间互联

如前所述,移动无线网络是不同提供商的集合。因此,这些提供商之间的对等互联与互联网的ISP非常相似,在互联网交换点使用IP互连。同样,这与4G之前的版本处理方式不同,那时有专门的语音服务互连。

SIM卡上的IMSI号码是全球唯一的标识符。因此,无论该设备连接到哪个网络,他们都可以查找该特定IMSI号码的归属网络。被访问的移动运营商网络随后会与归属网络核对,以了解他们能够为支持该用户向归属网络收取哪些服务费用。


迈向5G

如今,我们开始看到5G的部署。让我们看看有什么不同。这里有一个显著的目标是增加带宽。然而,我们应该注意到,4G从未广泛地向用户提供其能够达到的带宽。即使4G能够达到数百兆比特每秒,用户体验通常只有个位数或几十兆比特每秒。因此,4G协议并不是向用户提供带宽的限制因素。

然而,转向5G的真正动机是能够在密集区域支持更多的移动设备,这意味着对多用户同时接入的支持得到了显著改善。5G还有两个新频段获得批准。我们注意到,这些频段(至少在高端)比过去通常使用的频率要高得多。这意味着它们的传播距离不会那么远,因此5G的小区在地理上会更小。然而,这在人口非常密集的地区是一个优势,因为它允许更大的频率复用。

这些更小的小区可能被称为微微小区,直径在几十或几百米。这意味着服务提供商将需要部署大量新的小区,这与基于大型塔楼、拥有相对较少小区的旧模式有显著不同。


总结

本节课中,我们一起学习了蜂窝4G和5G网络的工作原理。我们探讨了其整体架构、核心组件(如UE、基站、分组核心网、HSS、MME和网关),并理解了控制平面与数据平面的分离、隧道协议的作用以及移动性管理的关键概念。我们还了解了与基站关联的过程、电源管理的重要性、运营商间漫游机制,以及5G在支持高密度设备和采用新频段方面带来的主要变化。下一节,我们将深入探讨移动性管理的更多细节,包括其在蜂窝网络和移动IP网络中的应用。

7.4:移动IP如何工作 📡

在本节课中,我们将学习IP网络中如何处理移动性,包括蜂窝网络(4G/5G)和移动IP。我们将探讨移动性的定义、网络面临的挑战以及解决这些挑战的不同技术方案。


移动性的定义与挑战

上一节我们介绍了蜂窝网络的架构,本节中我们来看看移动性处理的具体细节。正如我们在课程中多次提到的,分组网络协议最初是为有线网络设计的,并未充分考虑移动性。因此,在这些环境中处理移动性一直是个挑战,需要专门的技术。

首先,我们需要定义在此上下文中的“移动性”意味着什么。从网络角度看,移动性有不同的级别:

以下是移动性的几个级别:

  • 无移动性:设备如果移动,必须在移动过程中关机,并在连接到新网络时从头开始。网络只需处理设备在一个地方断开,在另一个地方连接。
  • 本地移动性:例如,在连接Wi-Fi时在屋内移动。你仍连接到同一个接入点,网络拓扑没有实时变化,只是无线链路提供了无束缚的连接。这类似于在蜂窝网络中,设备在连接到同一基站时移动。
  • 网络内移动:设备从一个接入点移动到另一个,但仍在同一个公司网络或局域网内。例如,在家或企业中有两个接入点,并在其间无缝切换;或在移动无线环境中,从一个小区移动到另一个,但服务提供商不变。
  • 高移动性:设备从一个提供商的网络移动到另一个,同时保持活跃的连接。请回想网络套接字,套接字的一部分是它所连接的IP地址。因此,如果你的IP地址改变,所有基于套接字的连接都会中断。我们这里讨论的移动性是指设备在保持相同IP地址的情况下跨提供商移动,并且数据包能够从其旧位置路由到新位置,而不会造成显著中断。

我们已经很好地理解了设备如何断开或重新连接到网络,以及如何在连接到一个接入点时移动。因此,我们真正关注的是上述级别中靠右的部分,包括基站间的切换以及从一个提供商到另一个提供商的切换。


处理移动性的可能方法

我们有不同的潜在方法来实现这一点。

一种方法是让现有的IP路由来处理。这意味着如果你的IP地址移动到了新位置,新网络就接受它,并开始通告到达你这个独立IP地址的路由路径。从技术上讲,基础设施支持这样做,路由表中通告单个IP地址并无障碍。

阻止我们这样做的是规模问题。目前互联网支持大约数十万条路由。将其扩展到数十亿台设备,会给互联网核心带来巨大负载,而互联网核心并非为此设计。因此,从实践角度看,让网络使用现有IP路由协议来处理移动性并不可行。

那么,我们能在网络边缘做什么呢?这实际上意味着在网络之上创建一个覆盖层,通信总是先到达归属网络,然后被转发到受访网络。因此,当设备移动到新网络时,它会获得一个与该受访网络关联的地址,然后归属网络会更新以知晓这个新地址。


类比与社会网络

我们可以将其与社交网络中的一个问题联系起来:与朋友失联一段时间后,你发现他们搬家了,或者他们经常旅行。

以下是几种可能的解决方案:

  • 搜索所有电话簿:这类似于让核心路由表处理所有移动设备,规模上不可行。
  • 期望朋友每次搬家都通知你和所有其他朋友:这同样难以扩展。
  • 联系一个“家”或“亲戚”来获取朋友的最新位置:这更接近我们讨论的思路。
  • 存在一个权威或确定的信息源:这个信息源会在任何变更时更新,并且其他方有办法找到这个信息。

我们从类比中得到的想法是:某处存在关于你(或在移动网络情况下是关于设备)信息的权威或确定来源,并且该信息源会在发生任何变更时更新,同时其他方有办法找到该信息。


蜂窝网络与固定网络的对比

回到我们的蜂窝网络示例。我们有归属网络和受访网络,它们都连接到互联网交换点。我们的移动用户设备与某个订户有服务计划,该订户维护着该用户的信息。然而,此时设备不在归属网络范围内,它实际上连接到了受访网络。但使用IMSI号码,受访网络能够通过归属网络查找该订户的信息。

相比之下,对于Wi-Fi或家庭ISP,我们没有这种强烈的“归属”概念。如果你的设备连接到其他地方的ISP,它就不再使用你的家庭服务计划,而是使用该位置的服务计划。因此,传统的固定无线宽带服务提供商非常注重位置——他们为你的家庭地址或企业提供服务,但该服务不会在你连接到其他网络时跟随你。如果你连接到不同的网络,你会有不同的凭证、不同的服务计划等。

稍后我们将看到关于移动IP的信息,它旨在直接在IP上实现这种漫游行为。但在实践中,它的使用远不如蜂窝数据网络广泛。


通用模型与间接路由

我们可以将归属网络和受访网络的概念通用化,并看一个带有地址的示例。我们有三个网络都通过公共互联网连接,每个网络都有一个唯一的/16地址块。其中一个网络拥有特定用户的归属信息。然而,该设备连接到了受访网络,并在该网络中获取了一个临时IP地址,并提供了其IMSI号码。

因此,使该设备能够通过归属网络进行通信,将涉及归属网络的归属订户服务器和两个网络的移动性管理器。互联网上的某处有一个通信对端,即需要与该移动订户通信的设备。哪个设备发起连接并不重要,因为我们知道大多数应用程序在TCP上运行,这需要数据包的双向流动。

为了使这能工作,移动设备必须通过受访网络向归属网络注册。作为关联过程的一部分,移动设备将与受访网络的移动性管理器通信,而移动性管理器将通知归属网络该设备现在连接到了这个受访网络。因此,现在归属网络和受访网络都知道设备的新位置。

然而,通信对端只知道该订户的归属IP信息。因此,当数据包被发送到归属网络中的地址时,归属网络需要将其转发到受访网络,再由受访网络转发给订户。

从移动设备返回通信对端的流量,在概念上可以直接发送给通信对端。然而,大多数应用程序无法理解这一点,因为这样数据包将来自一个与预期不同的IP地址。因此,通常返回的流量会先回到归属网络,然后从那里转发给通信对端。

这样做的好处是移动设备的IP地址不会改变,因此它能够在网络间移动时保持这些连接。然而,存在一个低效之处:流量总是必须经过归属网络,这可能会大大增加流量的路径长度。


直接路由方案

另一种方案是使用支持移动性的直接路由。在这种情况下,当通信对端与归属网络通信时,归属网络告诉通信对端:“这是新地址”。然后由通信对端重新尝试连接并与受访网络通信。接着,受访网络将流量传递给移动设备。因此,后续的通信可以直接在通信对端和移动设备之间通过受访网络进行,而无需经过归属网络形成路由三角。

这种方案的优点是流量的路径是直接的,不必让所有数据都经过归属网络。然而,许多应用程序无法理解这个过程,因此它仅限于那些对移动性处理有特定概念的专门应用程序。此外,还存在处理连接建立后设备再次变更网络的问题,这也需要一种机制来处理而不中断连接。


实际系统中的应用

我们讨论了几种处理分组网络移动性的不同方案。现在我们将看看它们如何在几个实际系统中部署,包括蜂窝网络和移动IP。

在4G网络中,移动设备与基站关联,正如我们在上一个视频中看到的。在关联过程中,它向受访网络提供其IMSI号码。受访网络然后与归属订户服务器通信,让其知道该设备现在的位置。

然后,移动性管理器可以建立我们在上一个视频中谈到的隧道,以在移动设备和归属网络之间传输数据流量。网络还支持切换,即设备可以从一个附着点移动到另一个,隧道会被相应地转发。

在控制平面方面,有一个基站控制平面信道,设备可以用它与移动性管理器通信。这就是它如何将IMSI号码传递给移动性管理器,移动性管理器然后使用它联系归属网络并获取诸如认证信息(证明其有活跃服务)和加密密钥等。

在基站和移动设备之间,为无线链路选择参数。

服务网关然后需要与基站建立隧道。因此,当移动设备改变其连接点时,设备的IP地址不会改变,但隧道的端点会改变为新的路由器。然后,服务网关还建立一个隧道回到归属网络的分组网关。这遵循了我们之前几张幻灯片中看到的间接路由模式。

移动设备的应用程序(很可能是基于IP的TCP数据包)然后被封装在隧道内,而隧道又位于UDP数据包内的IP数据包中。因此,协议有显著的嵌套,这会影响我们在前几章中看到的MTU等问题。


切换过程详解

尽管我们刚刚提到基站间的切换可以发生,但让我们看看这个过程涉及什么。我们原始的数据路径是从设备到源基站,通过隧道到达服务网关。

切换后,设备将通过隧道与目标基站通信,再到达服务网关。在链路层,设备的无线电与基站通信,实际上它一直从多个基站接收信号,因此在切换发生之前,它已经与目标基站有某种程度的通信。

现在需要注意的一个重要点是,手机本身并不决定何时切换到新基站,而是由源基站告知其进行切换。在此之前,源基站向目标基站发送切换请求。目标基站然后可以在时分复用无线方案中分配时隙,并回复源基站,将此信息传递给手机。源基站告诉移动设备关于新基站的新设置,然后手机可以与新基站通信。因此,此时源基站开始将流量转发到新基站,移动设备与新基站通信,从手机的角度看事情完成了。

然而,在网络核心,新基站必须与移动性管理器通信,以便移动性管理器可以更改服务网关上的隧道配置。一旦完成,数据包就可以直接在服务网关和目标基站之间流动。最后,源基站可以释放资源并退出循环。


移动IP架构

远早于4G,我们有了移动IP架构。其理念是允许移动IP设备在保持相同IP地址的同时,从一个无线接入点漫游到另一个。这里建立的架构类似于后来在4G场景中采用的方案。

然而,我们看到术语上的一些差异。在移动IP中,我们提到归属代理和外部代理。仍然有强烈的归属网络和受访网络的概念,但我们称受访网络为外部网络,在该网络上运行以支持移动IP的服务是外部代理。注册新访问位置的信号通过特定的ICMP消息处理。

从历史上看,移动IP架构对当今蜂窝网络的运作方式产生了重大影响。然而,移动IP本身从未作为一项服务流行起来,原因多种多样,其中一些是“先有鸡还是先有蛋”的问题:一个组织部署移动IP直到许多其他组织也部署移动IP才能受益,并且需要有一些商业模式来确定如何通过部署这些服务产生收入。这一切从未在移动IP上实现。


移动性对其他协议层的影响

让我们看看移动性对我们之前讨论过的协议栈其他层施加的一些考虑因素。

正如我们所说,移动IP的技术目标是使设备能够在移动时保留相同的IP地址,从而保持其已建立的通信流。然而,在实践中,在从一个位置切换到另一个位置的过程中,数据包有可能丢失或乱序。正如我们所知,TCP对丢包非常敏感,任何时候丢包,它都假设存在拥塞,因此会将其发送速率降低50%。此外还有延迟问题:如果提供的服务是实时服务,如语音通话或视频通话,切换过程中给数据包增加的延迟可能会在通话质量中体现出来。


本章总结

这把我们带到了第7章的结尾。我们讨论了无线链路的特性以及这给网络协议带来的挑战。我们专注于两个主要技术领域:802.11无线局域网技术(或无线以太网),以及蜂窝4G和5G网络。为了理解它们如何工作,我们深入研究了处理移动性的具体细节。总的来说,就是归属网络受访网络这一原则,使得远程用户即使在设备从一个网络漫游到另一个网络时,也能定位并与移动设备通信。

这就是本视频的全部内容。在第8章,我们将探讨网络安全问题。希望你喜欢这个视频。如果觉得有用,请点击“赞”按钮。要在此课程发布更多视频时收到通知,请订阅我们的频道并点击铃铛图标。

8.1:什么是网络安全? 🔐

在本节课中,我们将探讨“什么是网络安全?”这个问题。我们将明确网络安全与其他类型系统安全(如密码学)的区别,并概述本章将要学习的核心概念。

概述

欢迎回来。今天我们将讨论网络安全。我们将区分网络安全与系统安全或密码学等专门领域的不同之处。

在深入第8章的具体主题之前,我们需要明确“网络安全”的范畴。我们选择的是那些网络环境在系统安全实现中扮演重要角色的特定主题。构建一个安全的系统涉及许多其他方面,包括物理安全、密码学细节、应用设计、系统架构本身(避免单点故障),以及列举所有可能构成威胁模型的不同攻击类型和挑战。

因此,本章不仅聚焦于网络安全,而且只关注最常用的网络安全方面。Kurose和Ross的章节未涉及一些更高级的主题,例如无线网络安全,这些可能在后续视频中讨论。

本章内容概览

以下是本章将要学习的主要主题。

首先,我们将概述密码学。需要指出的是,网络领域本质上是密码学领域的“客户”。有专家负责设计和标准化密码协议,然后网络协议去实现这些密码标准。因此,我们不会深究密码学背后的数学细节,而是关注如何在网络环境中使用密码学。

接着,我们将学习认证消息完整性。请注意,消息完整性意味着消息在传输过程中不能被篡改,且接收方能发现篡改。消息完整性并不保证第三方无法读取消息。

在理解这些基础知识后,我们将继续研究网络协议和应用的具体实例,看它们如何实现这些安全原语。

在本视频的剩余部分,我们将只介绍网络安全的基本含义。

网络安全的基本目标

当我们谈论安全时,首先想到的可能是机密性。这意味着第三方不应能够读取发送的消息,只有发送方和接收方应知道消息内容。这是通过在发送方加密消息,在接收方解密消息来实现的。其思维模型是:在发送端有意义的比特流,被“打乱”成对可能正在监听线路的第三方毫无意义的形式,然后在接收端逆转此过程。

然而,我们必须注意,为了实现这一点,发送方和接收方之间必须有一个共享的秘密,即加密密钥。网络协议通常容易出问题的地方,正是在于如何以一种不会被第三方截获或削弱加密安全性的方式交换这个共享密钥。

第二个目标是认证。如果你熟悉AAA安全模型,认证就是第一个“A”。其核心思想是确认通信参与者(发送方或接收方)的身份。AAA安全模型中的另外两个“A”是授权计费,这些概念我们今天不常思考,但在实践中一直使用。例如,从服务提供商的角度,他们希望认证用户是支付服务费用的人,然后通过授权检查该用户有资格使用哪些服务,最后计费该实体使用了多少服务。

第三个常见的网络安全目标是消息完整性。我们可能不关心消息是否被第三方读取,但我们希望确保消息在到达接收方时确实是它应有的内容,并且没有人在途中未经我们发现就篡改了它。

我们还面临访问和可用性的问题。关键在于,安全机制必须对所有用户(包括非技术用户)可用,因此这些机制必须是无缝且自动化的,以便任何人都能从中受益。

实例分析

现在让我们看一些例子。假设我们有Alice、Bob和攻击者Trudy。Alice和Bob希望安全地相互通信,他们的“安全”定义是消息保密。

这里的攻击者Trudy可以在消息通过网络时截获、删除或添加消息。

当然,Alice和Bob不仅仅是名为Alice和Bob的真实人物,他们代表所有可能连接到网络的不同实体。一个非常常见的例子是电子商务,即进行购买、传输信用卡信息或其他形式电子支付的电子交易。如果第三方能够截获这些信息,他们可能会从用户那里进行经济盗窃。

另一个例子是网上银行,用户的私人财务信息通过网络传输,暴露这些细节也可能导致用户经济损失。

另一个可能未得到足够重视的应用是DNS服务器。虽然许多人都熟悉与网站通信时需要端到端加密,并在浏览器中寻找绿色的HTTPS或锁图标,但他们没有意识到,在建立连接之前,他们的计算机会发送一个针对该特定网站的DNS请求,而这个DNS请求是明文发送的。正如我们在DNS协议中看到的,它不提供任何安全性。因此,不仅他们的ISP和路径上任何关注的人都知道他们打算访问哪个网站,甚至答案也可能被更改。恶意攻击者可以重写DNS回复,将用户引导到与DNS服务器实际提供的IP地址不同的地址。这是一个巨大的漏洞。我们确实有DNSSEC协议,但它远不如HTTPS那样被广泛使用。

另一个例子可能是使用BGP交换路由表更新的路由器。同样,如果这些更新未加密,恶意攻击者可能能够更改它们,并以此方式劫持流量。

我们还可以想到许多其他例子,例如需要在不被检测到的情况下传递信息的举报人,或者需要能够在传输过程中不被篡改或读取消息的记者或其他社会正义行动者。当然,这样的例子不胜枚举。

威胁模型

我们一直在提及这些攻击者或“坏人”,但我们还没有真正说明我们的威胁模型是什么,即坏人能做什么?

答案是相当多的。最简单的大概是窃听,即截获并读取消息。更高级的能力是向连接中插入消息。除此之外,也许是假冒,即伪造源地址,使消息看起来来自并非真实的发送者。我们还可能想到劫持,即不仅仅是截获正在进行的连接通信,而是实际接管连接的一端并替换发送方或接收方。最后,还有拒绝服务。这里并非特指DDoS攻击,而是指任何阻止连接继续并实现其预期服务目标的行为。

总结

本节课中,我们一起学习了网络安全的基本定义及其核心目标:机密性、认证、消息完整性以及访问和可用性。我们还通过实例分析了不同场景下的安全需求,并初步探讨了攻击者可能构成的威胁模型。

这结束了我们简短的介绍。在下一个视频中,我们将探讨密码学的原理。

8.2:密码学原理 🔐

在本节课中,我们将要学习密码学的基本原理。我们将讨论两种主要的加密方法:对称密钥密码学和公钥密码学。需要指出的是,网络领域主要是现有密码学算法的使用者,因此我们不会深入探讨其背后的数学细节,而是重点介绍这些方案如何应用于网络环境。

加密的基本概念

上一节我们介绍了课程概述,本节中我们来看看加密系统的基本构成和术语。

首先,我们需要一些通用术语来帮助我们讨论这些系统。从左到右看,我们有明文。这是原始数据,对用户或创建它的程序来说是有意义的。明文经过加密算法处理,该算法还需要一个加密密钥。加密算法产生的结果是密文。我们通常用 K_A(M) 来表示密文,意思是使用加密密钥 K_AM 进行了加密。

当密文到达解密算法时,会应用解密密钥,我们称之为 K_B。解密算法应该产生的结果是明文。因此,明文应等于密文 K_A(M) 使用 K_B 处理后的结果,再次得到原始的明文消息 M。我们希望中间的密文具有某些特性,特别是密文中不应有任何特征能让攻击者轻易猜出原始明文。

攻击者的策略

了解了加密流程后,我们来看看攻击者可能采取的不同攻击方法。

我们通常考虑唯密文攻击,即攻击者能够截获密文,将其保存下来进行分析。他们可以对该密文进行统计分析,或进行暴力破解攻击,即尝试所有可能的密钥。如果加密算法是理想的,统计分析不会产生任何有用的信息,因此不会比暴力破解更容易。然而,对于任何设计良好的加密算法,暴力破解在时间和处理能力上都非常昂贵,因此攻击者会寻找一些优势来缩小搜索空间。

以下是攻击者可能采取的几种策略:

  • 已知明文攻击:即使不知道密钥,如果攻击者能同时获得一份明文样本和对应的密文,他们可能能够逆向推导出所使用的密钥。
  • 选择明文攻击:攻击者实际上可以选择一条消息进行加密,并获得该消息的明文和密文。这里需要注意,如果网络协议导致已知字符串(例如,作为协议头的一部分)被加密,这可能会给攻击者提供破解加密的途径,即使底层使用的算法本身是安全的。

对称密钥密码学 🔑

现在,我们将通过区分对称密钥密码学和公钥密码学来进一步分解内容。这两种方法在网络系统中都广泛使用。首先,我们来看对称密钥的情况。

在对称密钥密码学中,明文输入后,使用密钥 K_S 进行加密,密文在网络中传输,并使用相同的密钥 K_S 进行解密。因此,爱丽丝和鲍勃共享同一个密钥进行加密和解密。例如,密钥可以是单字母替换密码中的替换模式。

对称密钥面临的核心问题是:如果爱丽丝和鲍勃都需要拥有相同的密钥,他们如何就密钥值达成一致?这正是网络协议通常发挥作用的地方。但我们必须注意这里存在一个引导问题:爱丽丝不能直接把密钥发送给鲍勃,因为如果她加密发送,鲍勃将无法知道密钥是什么;如果她以明文发送,那么任何在中间监听连接的人也会获得密钥,这将使加密消息的目的落空。因此,关键在于密钥交换协议

对称密钥示例:替换密码

为了更直观地理解,我们来看一个替换密码的例子。我们有一个明文,在这个例子中就是字母表。我们的密文是取每个字母并用另一个不同的字母替换它,这是一一对应的,意味着每个字母映射到一个不同的字母,没有重复,否则替换密码将不可逆。

如果我们应用这个映射到一个句子上,例如爱丽丝说“Bob, I love you. Alice.”,我们查看上面的映射,逐个字母替换:B变成n,O变成K,等等。然后密文被发送出去。我们的加密密钥就是这个映射表。

然而,替换密码存在许多问题,这是一个可能使用统计攻击的例子。例如,众所周知,英文字母表中某些字母的使用频率远高于其他字母。因此,如果进行这种频率分析,你可以找出元音和空格的替换规则,一旦找到单词边界,就可以分析单词长度、常用代词和副词等。只要有足够的密文,就可以逆向推导出替换密钥。所以在实践中,我们需要比这安全得多的东西。一种方法可能是使用多个替换密码并在它们之间轮换,这可以防止有足够的每个模式的密文来进行统计分析。

现代对称密钥算法

一个常见的对称密钥密码方案是DES。它使用56位密钥,明文输入以64位块为单位进行加密,并且存在密码块链接模式。然而,从计算技术角度来看,这个标准相当古老。目前,DES可以在不到一天的时间内通过暴力破解解密。不过,它在没有良好分析性攻击的意义上是安全的,即没有统计特征能让攻击者逆向破解它。但由于暴力破解相对较快,实践中通过执行加密三次来改进DES,即使用三个不同的密钥对明文加密成密文,然后将该密文再次加密成新的密文,再重复一次。这样做的一个显著优势是,当你有一个密文时,它看起来是随机的。因此,如果你试图暴力破解一个已经是加密密文的密文,即使你正确反转了一次,得到的仍然是随机输出,所以这不仅仅是寻找三个密钥的时间增加了三倍,而是必须尝试三个密钥的所有组合,搜索空间急剧增大,暴力破解更加耗时。

更近期的标准是AES,它实际上已经取代了当今大多数系统中的DES。它使用更大的块大小以提高效率,并拥有更大的密钥空间。因此,对于这种方案,对DES只需1秒的暴力破解,对AES则需要149万亿年。

公钥密码学 🌐

现在让我们谈谈密码学的另一种方法——公钥密码学。需要提前说明的是,公钥密码学并非对称密钥密码学的替代品,它们各有其位置、优势和劣势。因此,我们需要理解它们的不同之处以及各自的应用场景。

如前所述,对称密钥加密要求发送方和接收方都知道这个共享的秘密。但我们也说过,这些机制必须对所有用户可用,而大多数用户之前从未见过面,也没有任何带外通信渠道。那么,他们最初如何在不发送明文的情况下就密钥达成一致呢?

公钥密码学采取了一种截然不同的方法:发送方和接收方不共享秘密密钥。公钥是所有人都知道的,但私钥只有接收者知道。这意味着任何人都可以用接收者的公钥加密消息并发送给他,但路径上的任何人都无法解密该消息,因为解密密钥与加密密钥不同,且只有接收者知道其私钥。

公钥加密流程

现在我们有爱丽丝和鲍勃,爱丽丝发送她的明文消息,加密算法的输入现在是鲍勃的公钥。爱丽丝需要查找鲍勃的公钥,但由于它是公开的,可以放在鲍勃的网站上或某个公钥数据库中,任何人都可以找到它并加密消息发送给鲍勃。因此,我们现在有了这个密文,即使用鲍勃公钥加密的消息。然后,解密算法的输入是鲍勃的私钥。我们在这条连接的两端使用不同的密钥。算法的工作原理是,用公钥加密的消息再经过私钥处理,就得到了原始的明文消息。

值得注意的是,几千年来,对称密钥加密是唯一已知的加密类型,而公钥密码学的思想是相当近期且具有革命性的。

RSA算法

为了使公钥加密算法工作,我们需要这些匹配的密钥——一个公钥和私钥组成的密钥对,使得用一个加密的内容可以用另一个解密。我们还需要注意,给定一个公钥,应该不可能推导出私钥,这听起来显而易见,但指出这是该算法成功的要求很重要。

最广为人知的算法是RSA。理解RSA的一个前提是理解模运算。这通常在编程语言中用百分号表示。所以 x mod n 给出 x 除以 n 的余数。模运算有一些有趣的特性,这些特性对于理解算法很有用。但最终,我们想展示的是 (a mod n)^d mod n 等于 a^d mod n

从RSA的角度来看,消息只是一个比特模式。我们一直用明文来讨论消息,因为这更容易理解和解释,但重要的是要注意,这些消息只是需要加密的任何比特序列。任何比特模式都可以唯一地表示为一个整数,因此加密消息等同于加密一个数字,无论这些比特代表字母、二进制数据还是其他什么。

为了使用我们的公钥加密算法,我们必须创建一个公钥和私钥对,这些密钥是从素数派生出来的。首先,我们选择两个大素数。然后需要计算 N = p * q。同时计算 z = (p-1) * (q-1)。接着,我们选择一个值 e,它小于 n 且与 z 没有公因数,即 ez 互质。然后我们选择一个值 d,使得 e*d - 1 能被 z 整除,这意味着 e*d mod z = 1。一旦我们有了这些值,我们的公钥就是数对 (n, e),我们的私钥就是数对 (n, d)

那么,我们如何使用这些来进行加密和解密呢?我们假设已经计算好了 ned 的值。要计算密文 C,我们取消息 M(我们的字节序列),计算 C = M^e mod n。在解密端,我们取密文 C,计算 C^d mod n,结果就是我们的原始消息 M。换句话说,M = (M^e mod n)^d mod n

RSA还拥有另一个非常重要的特性,这在后来变得非常有用:操作可以按任意顺序执行。我们可以用加密密钥加密,然后用解密密钥解密;或者用公钥加密,用私钥解密。但我们也可以颠倒顺序:用私钥加密,然后任何拥有公钥的人都可以解密它。这是因为我们之前看到的所有模运算特性都是可逆的,并且顺序无关紧要。

公钥密码学的安全性与应用

从我们的角度来看,我们真正关心的是:为什么RSA是安全的?如果我们知道公钥(我们很可能知道,因为它是公开的),那么确定解密密钥 d 有多难?本质上,我们必须在不知道两个因子 pq 的情况下找到 n 的因子。这里的关键点是,分解一个大数在计算上是困难的。因此,一个重要结论是:我们建立在互联网安全基础设施之上的公钥加密方案,依赖于分解大数很困难这一事实。如果分解大数变得容易,我们将不得不重新思考当今在互联网上实现安全的整个方式。

那么,如果RSA这么好,为什么我们不直接使用它呢?实际上,RSA在计算上非常密集,即使我们有了这些大密钥,使用大指数进行加密和解密的过程也非常慢。DES至少比RSA快100倍,AES也比RSA快得多。因此,在实践中,我们使用公钥密码学来建立安全通信。还记得我们说过对称密钥的问题在于必须将对称密钥从发送方传递给接收方吗?现在,爱丽丝可以用鲍勃的公钥加密对称密钥,这样鲍勃就可以解密出对称密钥,然后在会话的后续部分使用对称密钥。这种对称密钥算法的运行速度比公钥算法快得多,因此我们获得了传输大量数据所需的性能。

总结

本节课中我们一起学习了密码学的基本原理。我们首先介绍了加密的基本概念和术语,包括明文、密文、加密密钥和解密密钥。接着,我们探讨了攻击者可能采取的几种策略,如唯密文攻击、已知明文攻击和选择明文攻击。

然后,我们深入比较了两种主要的加密方法:对称密钥密码学和公钥密码学。在对称密钥部分,我们以替换密码为例说明了其原理和弱点,并介绍了现代算法如DES和AES。在公钥密码学部分,我们重点讲解了RSA算法的工作原理、密钥生成过程以及其依赖的数学难题——大数分解的困难性。

最后,我们了解到,由于性能考虑,实际网络通信中常常结合使用这两种技术:用公钥密码学安全地交换一个对称会话密钥,然后用对称密钥加密实际传输的数据,从而兼顾安全性与效率。这为我们理解后续章节中将探讨的网络认证和消息完整性等安全原则奠定了基础。

8.3:消息完整性、数字签名与认证协议 🔐

在本节课中,我们将学习网络安全的两个核心目标:消息完整性认证。我们将从基础的密码学工具出发,逐步构建一个安全的认证协议,并理解数字签名和证书颁发机构在其中扮演的关键角色。


上一节我们介绍了对称密钥和公钥密码学的基本原理。本节中,我们来看看如何利用这些工具来实现身份认证和确保消息在传输过程中未被篡改。

认证的挑战:从简单到复杂

设想一个场景:Bob想要确认正在与他通信的是Alice。一个简单的声明“我是Alice”显然不足以保证身份的真实性,因为攻击者Trudy也可以发送完全相同的比特流。

尝试一:使用IP地址

在数据包中,除了“我是Alice”的声明,还包含了Alice的源IP地址。然而,攻击者可以轻易地伪造(Spoof)IP地址,因此这并非可靠的身份验证方法。

尝试二:使用密码

Alice向Bob发送她的秘密密码以证明身份。Bob确认后回复“OK”。这种方法存在一个致命缺陷:重放攻击(Replay Attack)。如果攻击者Trudy窃听了这次通信,她可以保存包含密码的数据包,并在未来任何时候重新发送它。对Bob而言,这个重放的包与来自Alice的原始包同样“合法”。

尝试三:加密密码

为了改进,Alice使用Bob的公钥加密她的密码后再发送。遗憾的是,重放攻击依然有效。攻击者无需知道密码明文,只需重放加密后的密文即可。

尝试四:引入一次性随机数(Nonce)

为了彻底杜绝重放攻击,协议引入了一次性随机数(Nonce),即一个“一生只用一次”的数字。

  1. Alice说:“我是Alice”。
  2. Bob回复一个随机数R,并说:“证明给我看”。
  3. Alice使用她与Bob的共享密钥加密这个随机数R,并将结果发回给Bob。
  4. Bob解密后验证随机数是否匹配。

这个协议解决了重放问题,但引入了一个新前提:Alice和Bob必须事先拥有一个共享密钥。我们尚未讨论如何安全地建立这个共享密钥。

尝试五:使用公钥密码学

我们尝试用公钥密码学替代共享密钥。

  1. Alice说:“我是Alice”。
  2. Bob回复一个随机数R。
  3. Alice使用她的私钥加密R,即计算 K_A^-(R),并发回给Bob。
  4. Bob需要Alice的公钥来解密验证。Alice可以提供她的公钥,或者Bob从其他可信来源获取。

然而,这个协议仍然存在一个严重的安全漏洞:中间人攻击(Man-in-the-Middle Attack)

以下是攻击过程:

  1. Trudy截获Alice发给Bob的“我是Alice”消息,并原样转发给Bob。
  2. Bob将随机数R发给Trudy(Bob以为是在发给Alice)。
  3. Trudy将R转发给真正的Alice。
  4. Alice用她的私钥加密R后发回。
  5. Trudy截获这个加密结果,并转发给Bob。
  6. 当Bob索要公钥时,Trudy可以提供她自己的公钥。
  7. Bob用Trudy的公钥解密,验证通过(因为加密使用的是Trudy的私钥),从而错误地相信Trudy就是Alice。

此后,Bob发送给“Alice”的机密信息,实际上是用Trudy的公钥加密的,Trudy可以解密阅读,再用Alice的公钥加密后转发。Alice和Bob对此毫不知情。

那么,这个协议的漏洞在哪里?我们又该如何修复它?答案是,我们必须先深入理解消息完整性


上一节我们看到了缺乏消息完整性如何导致认证协议失败。本节中,我们来详细探讨消息完整性和数字签名。

消息完整性与数字签名

消息完整性意味着接收方能够确认消息在传输过程中是否被篡改。数字签名类似于手写签名,旨在提供证据,证明消息来自其声称的发送者且内容完整。

我们希望数字签名具有以下属性:

  • 可验证性:接收方能确认这是发送者的签名。
  • 不可伪造性:只有发送者能生成有效的签名。
  • 不可抵赖性:发送者事后不能否认他签发了该消息。

基于公钥密码学的简单签名

一种简单的方法是:发送者Bob用他的私钥加密整个消息。

  • 生成签名签名 = K_B^-(消息)
  • 验证签名:任何拥有Bob公钥K_B^+的人都可以解密该签名。如果能用K_B^+成功解密并得到原始消息,则证明该消息必定是由持有对应私钥K_B^-的Bob签发的,并且消息内容完整。

然而,公钥加密计算开销很大,对长消息进行全程加密效率低下。

使用密码散列函数(哈希函数)

为了解决效率问题,我们引入密码散列函数。哈希函数能将任意长度的输入(消息)快速映射为固定长度的输出,称为消息摘要指纹

哈希函数的关键特性:

  • 定长输出:例如,SHA-256生成256位的摘要。
  • 单向性:给定摘要,在计算上不可能反推出原始消息。
  • 抗碰撞性:在计算上难以找到两个不同的消息产生相同的摘要。

常用哈希函数包括MD5(128位)、SHA-1(160位)和更安全的SHA-256等。

完整的数字签名流程

结合哈希函数和公钥加密,高效的数字签名流程如下:

发送方(Bob)操作:

  1. 对原始长消息m应用哈希函数H,得到定长的消息摘要 d = H(m)
  2. 使用Bob的私钥K_B^-对摘要d进行加密,生成数字签名 s = K_B^-(d)
  3. 原始消息m数字签名s一起发送给接收方。

接收方(Alice)操作:

  1. 收到ms
  2. 使用Bob的公钥K_B^+解密签名,得到摘要 d' = K_B^+(s)
  3. 对收到的原始消息m应用相同的哈希函数H,计算得到本地摘要 d = H(m)
  4. 比较d‘d
    • 如果 d‘ == d,则证明:a) 消息确实来自Bob(因为只有他有私钥能生成s);b) 消息m在传输中未被篡改。
    • 如果不相等,则说明消息被篡改或签名无效,消息不可信。


现在,我们理解了消息完整性的重要性,可以回过头来修复之前失败的认证协议5.0了。

修复认证协议:引入证书颁发机构

之前协议的核心问题在于:公钥的分发过程不安全。Bob和Alice在交换公钥时,无法确认收到的公钥确实属于对方,从而让中间人Trudy有机可乘。

解决方案是引入一个受信任的第三方——证书颁发机构

证书颁发机构的作用

证书颁发机构负责将公钥与特定实体(个人、网站、设备)进行绑定

  1. 实体(如Alice)向CA注册其公钥,并提供线下身份证明。
  2. CA验证身份后,创建一个数字证书。该证书包含:
    • 实体的标识信息。
    • 实体的公钥。
    • CA用自己的私钥对整个证书内容进行的数字签名
  3. 这个证书相当于CA的权威声明:“我证明,这个公钥属于这个实体”。

修复后的协议流程

当Bob需要Alice的公钥时,他不再直接向Alice索要(这可能被截获和替换),而是向CA请求Alice的数字证书。

  1. Bob从CA获取Alice的证书。
  2. Bob使用CA的公钥(众所周知且预装在系统中)验证证书上CA的签名。验证通过,则信任此证书。
  3. Bob从证书中提取出Alice的公钥。

现在,Trudy无法再进行中间人攻击:

  • 她无法伪造一个包含她自己的公钥、却声称属于Alice的有效证书,因为她没有CA的私钥来签名。
  • 如果她尝试替换Bob收到的证书,Bob用CA公钥验证时会失败。
  • 因此,Trudy无法再冒充Alice与Bob通信,也无法在两者之间窃听和篡改消息。

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

  1. 认证的挑战:从简单声明到使用密码、随机数,逐步揭示了重放攻击和中间人攻击的风险。
  2. 消息完整性:确保消息在传输中未被篡改的重要性。
  3. 数字签名:结合哈希函数和公钥密码学,实现了高效、可验证且不可伪造的签名机制,其核心流程是对消息摘要进行私钥加密
  4. 证书颁发机构:作为可信第三方,通过签发和验证数字证书,解决了公钥安全分发和身份绑定的根本问题,从而修复了认证协议。

在下一节课中,我们将探讨如何将这些安全机制应用到具体场景中,例如保护电子邮件安全。

8.4:使用PGP加密实现安全电子邮件 🔐

在本节课中,我们将学习如何通过公钥认证技术,为电子邮件提供签名和加密功能,从而实现邮件的安全传输。我们将探讨保密性、完整性和认证这三个核心安全目标在电子邮件场景下的具体应用。

在上一节中,我们介绍了认证和消息完整性的基础知识。本节中,我们将看看这些知识如何应用于保护电子邮件这一实际场景。

通常,我们使用用户名和密码登录电子邮件服务。这实现了服务提供商对你的认证。然而,邮件内容本身并未受到保护。无论是你的邮件服务提供商,还是收件人的服务提供商,如果存在恶意行为者,他们都有可能截获、读取甚至篡改邮件内容。我们接下来讨论的,不是如何登录邮件服务,而是如何真正保护邮件内容本身。

实现邮件保密性 🔒

假设爱丽丝想发送一封保密邮件,她希望邮件内容在传输过程中不被截获和读取。

以下是实现保密性的步骤:

  1. 生成对称密钥:爱丽丝首先生成一个对称密钥 KS
  2. 加密邮件内容:她使用对称密钥 KS 和对称加密算法(如AES)加密明文消息 M,得到密文 KS(M)。使用对称加密是因为它对大量数据的加密效率远高于公钥加密。
  3. 加密对称密钥:为了将对称密钥 KS 安全地发送给鲍勃,爱丽丝使用鲍勃的公钥 K_B^+KS 进行加密,得到 K_B^+(KS)
  4. 发送组合数据:爱丽丝将加密后的消息 KS(M) 和加密后的对称密钥 K_B^+(KS) 一起发送给鲍勃。

在接收端,鲍勃的操作如下:

  1. 解密对称密钥:鲍勃使用自己的私钥 K_B^- 解密 K_B^+(KS),得到对称密钥 KS
  2. 解密邮件内容:鲍勃使用对称密钥 KS 解密 KS(M),得到原始明文消息 M

通过这个过程,我们实现了邮件的保密性。消息被加密,且共享密钥以安全的方式传输。

实现邮件完整性与认证 ✍️

然而,上述过程只保证了保密性,并未对发件人进行认证。任何人都可以生成一个对称密钥并用鲍勃的公钥加密。鲍勃虽然能阅读消息,但无法确认消息确实来自爱丽丝。

现在,假设爱丽丝不关心保密性,但她希望鲍勃能确认消息来自她本人,并且在传输途中未被篡改。这时就需要完整性和认证机制。

以下是实现完整性与认证的步骤:

  1. 生成消息摘要:爱丽丝对明文消息 M 应用哈希函数 H(如SHA-256),生成一个固定长度的消息摘要 H(M)
  2. 数字签名:爱丽丝使用自己的私钥 K_A^- 对消息摘要进行加密,生成数字签名 K_A^-(H(M))。这个签名同时提供了完整性和认证。
  3. 发送组合数据:爱丽丝将原始明文消息 M 和数字签名 K_A^-(H(M)) 一起发送给鲍勃。

在接收端,鲍勃的操作如下:

  1. 解密消息摘要:鲍勃使用爱丽丝的公钥 K_A^+ 解密数字签名 K_A^-(H(M)),得到爱丽丝计算的消息摘要 H(M)
  2. 计算并比对摘要:鲍勃自己对收到的明文消息 M 应用相同的哈希函数 H,计算得到一个新的消息摘要 H(M')
  3. 验证:鲍勃比较解密得到的 H(M) 和自己计算出的 H(M')。如果两者完全一致,则证明:1)消息在传输过程中未被篡改(完整性);2)消息确实是用爱丽丝的私钥签名的,因此必然来自爱丽丝(认证)。

结合保密性、完整性与认证 🛡️

在实际应用中,我们通常希望同时实现保密性、完整性和认证。这可以通过组合上述两种技术来完成:

  1. 爱丽丝先对消息进行签名(用私钥加密哈希值)。
  2. 然后,她将签名和原始消息一起,使用对称密钥加密。
  3. 最后,她用鲍勃的公钥加密对称密钥,并将所有加密后的数据发送给鲍勃。

鲍勃则反向操作:先用私钥解密对称密钥,再用对称密钥解密得到消息和签名,最后验证签名。

虽然设置过程可能稍显复杂,但独立的邮件客户端通常都提供配置密钥对的机制,以支持邮件的加密和数字签名功能。

本节课中,我们一起学习了如何使用PGP(Pretty Good Privacy)加密的原理来保护电子邮件。我们探讨了如何通过公钥加密体系实现邮件的保密性,以及如何通过数字签名实现邮件的完整性和发件人认证。理解这些基础机制,是掌握网络安全通信的关键一步。

在下一节视频中,我们将探讨TLS(传输层安全)协议,它是为HTTPS提供安全保障的核心机制。

8.5:保护传输层(HTTPS工作原理)🔐

在本节课中,我们将学习如何使用TLS协议来保护TCP会话。TLS是HTTPS等应用所依赖的底层安全机制。我们将从基础概念开始,逐步构建对TLS工作原理的理解。

概述:TLS与HTTPS

TLS,即传输层安全协议,是为网站提供HTTPS(安全HTTP)服务的核心机制。它可能是我们遇到的使用最广泛的安全协议。早期它主要用于电子商务或网页邮箱,如今绝大多数网站都已部署HTTPS,并且所有浏览器都支持它。

TLS服务结合了我们之前见过的多种密码学元素:它使用对称加密提供机密性,使用密码学哈希提供完整性,并使用公钥密码学提供身份认证。你可能也听说过SSL,它是提供相同服务的早期协议,现已被弃用并由TLS取代。尽管SSL的版本号更高,但当前版本TLS 1.3在技术上更先进。

构建一个简化的TLS协议

正如我们在课程中对其他协议所做的那样,我们将从基本元素开始构建,看看实现传输层安全需要什么。我们称这个简化协议为“玩具TLS”。

玩具TLS包含几个关键阶段:握手(使用证书和私钥等)、密钥派生数据传输以及连接关闭。在时序图中,这些阶段叠加在TCP交换之上。这意味着必须先建立TCP连接,然后才能发送TLS握手消息、获取公钥证书。

密钥交换与派生

获取证书后,客户端使用服务器的公钥加密一个主密钥。这个主密钥是一个共享秘密。与之前所见不同,主密钥将用于为TLS会话生成额外的会话密钥

这里的一个缺点是,在交换数据之前,我们引入了额外的往返时间开销。在TCP握手完成后,还需要进行TLS握手,这增加了连接开始前的延迟。

多密钥的必要性

出于安全考虑,将同一个密钥用于多个密码学功能是不好的做法。因此,在这个例子中,我们需要不同的密钥用于消息认证和加密。最终我们需要四个密钥:

  • 客户端到服务器的加密密钥
  • 客户端到服务器的消息认证密钥
  • 服务器到客户端的加密密钥
  • 服务器到客户端的消息认证密钥

所有这些密钥都将从一个密钥派生函数 中派生出来,该函数基于主密钥。

记录层:处理字节流

现在我们面临一个技术考量。TCP提供的是字节流抽象,它只是一系列从一端流向另一端的字节。那么问题是:我们是希望等待整个流结束才能解密和认证,还是采用其他方式?

在这个例子中,我们将把流分解为一系列记录。数据将以已知大小的块发送,每个记录会附带使用主密钥生成的消息认证码。这样,接收方可以在记录到达时立即处理,而无需等待整个流结束。每个记录使用对称密钥加密,然后传递给TCP。

潜在攻击与防护

那么这可能受到怎样的攻击呢?我们面临重排序的问题。因为TCP头部不受TLS机制保护,中间人可能篡改TCP头部,重新排序TCP数据包内的内容,然后发送出去。

我们还可能受到重放攻击,即中间人保存加密信息并在稍后发送。为了防范这些攻击,TLS内部会使用加密的序列号,并且这些序列号在后续连接中不会重用。

安全地关闭连接

我们还提到会有一个连接关闭过程。一个潜在的攻击是,攻击者可能通过伪造TCP连接关闭段来截断连接。回想一下,TCP标志位控制会话何时关闭,而这些标志位同样不受加密保护。

解决方案是引入记录类型,并设定一个特定的类型用于关闭。这个类型信息包含在加密数据内部,因此攻击者无法伪造。

TLS的应用接口与HTTP

TLS协议为应用程序提供了接口。从HTTP的角度看,原始版本的HTTP直接在TCP上运行,没有加密。而HTTP/2能够使用TLS接口。如果你也听说过HTTP/3,它是运行在QUIC之上的HTTP/2的精简版。QUIC运行在UDP之上,这是一个重大变化,QUIC协议承担了重排序、流量控制和拥塞控制的角色,完全在UDP上运行,而不是让TCP执行这些功能。

对于我们当前的讨论,我们关注的是HTTP运行在TLS之上,而TLS又运行在TCP/IP之上。

TLS 1.3的密码套件

TLS及其版本号(这里是1.3)定义了所谓的密码套件,即一组用于密钥交换和加密的特定机制。实际上,它对某些功能提供了多种选项,因此在握手期间,两端需要协商将使用哪些方案来生成和交换密钥等。

我们注意到,与TLS 1.2相比,TLS 1.3的密码套件选项更少。例如,RSA已不再作为密钥交换的选项,仅支持迪菲-赫尔曼。然后它使用AEAD进行加密和认证,并使用SHA-256作为其密码学哈希函数。

TLS握手过程详解

以下是TLS握手过程:

  1. 客户端问候:客户端在其数据包中指明它支持的密码套件,以及迪菲-赫尔曼密钥协商的参数。
  2. 服务器问候:服务器从客户端支持的可用选项中选择一个密码套件进行响应,确认密钥协商协议参数,并提供其签名的证书。
  3. 客户端验证与请求:客户端使用证书颁发机构的公钥解密并检查服务器证书。只要验证通过,它就可以生成主密钥并开始发出应用请求。

零往返时间握手

此外,还存在零往返时间握手的情况。如果客户端正在恢复与服务器的先前连接,即它已经有一些预先建立的信息,那么就有可能实现。这样,客户端能够使用先前连接的主密钥加密应用数据。然而,这容易受到重放攻击,因此必须谨慎规定其使用场景。

总结

本节课中,我们一起学习了TLS和HTTPS。我们了解了TLS如何通过握手、密钥派生和记录层来保护TCP连接,提供了机密性、完整性和身份认证。我们还探讨了其潜在的攻击面及防护措施,并简要介绍了TLS 1.3的密码套件和握手流程。

在下一个视频中,我们将探讨IPSec,可以将其视为网络层安全,而我们刚刚研究的是传输层安全

8.6:IPsec与VPN工作原理

在本节课中,我们将学习网络层安全协议,特别是IPsec。它是虚拟专用网络VPN 背后的核心安全机制。我们将探讨IPsec的两种工作模式、其核心协议、安全关联的建立过程以及它如何提供机密性、完整性和认证。


网络层安全概述

上一节我们介绍了传输层安全协议TLS,它在两个应用程序之间创建加密隧道。本节中,我们来看看如何将安全机制下移到网络层。

在网络层进行加密,意味着在两个IP主机之间加密流量,通常是在一台主机和一个路由器之间。由于位于网络层,IPsec提供数据报级别的加密,以及认证和完整性机制,旨在覆盖用户流量和控制流量。

通过在网络层实施安全机制,我们可以更轻松地保护所有类型的流量,例如DNS查询,而TLS无法保护这些流量。


IPsec的两种工作模式

IPsec有两种主要的工作模式。

以下是两种模式的说明:

  • 传输模式:仅对数据报的有效载荷进行加密和认证。原始IP头部保持不变。这种模式适用于端到端的安全通信。
  • 隧道模式:对整个原始数据报(包括头部和有效载荷)进行加密和认证。然后,这个加密后的数据报被封装在一个全新的IP数据报中,并拥有新的IP头部。这种模式通常被称为VPN

隧道模式会增加数据包大小,如果原始数据包已经接近最大传输单元大小,可能导致分片。


IPsec核心协议

IPsec包含两个主要协议,定义在不同的RFC中。

以下是这两个协议的说明:

  • 认证头部协议:提供认证数据完整性验证,但不加密有效载荷,因此不提供机密性。在实践中较少使用。
  • 封装安全载荷协议:提供认证、完整性验证,并通过加密有效载荷来提供机密性。通常所说的IPsec主要指ESP协议。

安全关联

在通过IPsec隧道发送数据之前,需要先建立安全关联。与TLS不同,IPsec的关联通常不会自动建立,需要进行高级配置。

安全关联的每一端都需要维护必要的状态信息,包括密钥信息。这与IP无连接的特性有显著不同,因此IPsec会给路由器带来更多的开销。

一个安全关联在路由器上存储的信息可能包括:

  • 关联标识符
  • 源接口和目标接口
  • 使用的加密算法类型
  • 加密密钥
  • 使用的完整性检查类型
  • 认证密钥

最佳实践要求为安全机制的不同部分使用不同的密钥。


封装安全载荷数据包结构

在隧道模式下,原始IP数据报被封装在IPsec数据报内部。

新的数据包结构如下:

  • 新的IP头部:包含隧道端点的IP地址。
  • ESP头部:包含安全参数索引序列号
  • 加密部分:包含原始IP数据报和ESP尾部。
  • ESP认证部分:提供完整性校验。

ESP尾部包含填充字段,因为块密码算法需要对特定大小的数据块进行操作。


发送端操作流程

在发送端路由器上,处理一个需要IPsec保护的数据报时,需要执行以下步骤:

以下是发送端处理流程:

  1. 将ESP尾部附加到原始数据上。
  2. 将原始数据和IP头部一起加密。
  3. 将ESP头部放在加密块的前面。
  4. 计算整个信息(ESP头部 + 加密块)的认证摘要。
  5. 将认证摘要附加在后面,形成新IP数据包的完整载荷。
  6. 添加新的IP头部。

序列号与防重放攻击

IPsec使用序列号来防止重放攻击,这与TCP的字节序列号不同。

IPsec序列号是一个计数器。每次通过安全关联发送一个数据报时,发送方就递增其序列号计数器,并将该值放入序列号字段。接收方维护一个期望接收的序列号窗口,可以检测并丢弃重复的数据包或攻击者重放的数据包。

需要注意的是,并非所有数据包都会通过安全关联发送,路由器会根据安全策略数据库中的规则进行筛选。


安全策略与关联数据库

路由器通过两个数据库来管理IPsec流量。

以下是这两个数据库的说明:

  • 安全策略数据库:指定哪些数据报需要应用IPsec安全处理。规则通常基于源/目的IP地址、协议号等字段进行匹配。
  • 安全关联数据库:存储所有已建立的安全关联的状态信息。当一个数据报被判定需要IPsec处理时,SPD会指示使用SAD中的哪个关联,并告知路由器应采取的步骤(如使用何种加密机制、发送到哪里等)。

IPsec提供的安全保障

假设攻击者位于两个IPsec路由器之间,但不知道预先共享的对称密钥。

IPsec可以提供以下保护:

  • 机密性:攻击者无法看到数据报的原始内容。在隧道模式下,也看不到原始IP地址和端口。
  • 完整性:攻击者无法在不被察觉的情况下篡改数据位。
  • 认证:攻击者无法冒充任一端的路由器,因为她不知道用于连接认证的密钥。
  • 防重放攻击:通过使用序列号,并配合密钥化的完整性检查,保护关联免受重放攻击。

密钥管理:IKE协议

对于大型系统,手动配置IPsec VPN不切实际。作为替代,我们使用互联网密钥交换协议来自动协商安全参数。

IKE支持两种认证模式:

  • 预共享密钥:双方从一个共享秘密开始,运行IKE算法相互认证并生成安全关联。预共享秘密本身不作为加密密钥,而是作为生成加密密钥和认证密钥的起点。
  • 公钥基础设施:双方使用自己的公钥-私钥对和证书,通过IKE相互认证,过程与TLS握手机制类似。

IKE协商分为两个阶段:

  1. 建立一个双向的IKE安全关联
  2. 利用这个安全的通道,来协商用于实际数据传输的IPsec安全关联对

总结

本节课中,我们一起学习了网络层安全协议IPsec。

IPsec使用IKE消息交换来协商使用的算法、会话密钥以及每个安全关联的标识符。它可以工作在认证头部模式或更常见的封装安全载荷模式,后者能提供数据机密性。IPsec可以在任何两个运行IP的系统之间建立,常见场景是终端主机与路由器或防火墙之间的通信。

在下一讲中,我们将探讨无线和移动网络中的安全,包括Wi-Fi和蜂窝网络。

8.7:无线与移动网络中的安全

概述

在本节课中,我们将要学习无线与移动网络中的安全机制,特别是802.11(Wi-Fi)网络的安全。由于无线介质的共享特性,攻击者更容易窃听和传输数据,因此安全措施至关重要。我们将重点探讨Wi-Fi保护接入(WPA)的认证与密钥交换过程。

Wi-Fi(802.11)安全简介

上一节我们介绍了移动节点与接入点的基本关联过程。本节中我们来看看在建立基本通信连接后,如何进行安全认证与密钥交换。

无线网络比有线网络更易受到攻击。在有线网络中,窃听光纤或铜缆需要物理接触且容易被发现,而在无线域中,攻击者可以悄无声息地记录或传输数据。

认证与加密机制

关联之后,移动设备需要交换凭证以进行网络认证。首要问题是需要何种类型的认证。

接入点本身会广播其支持的认证形式和加密方法。移动设备在关联时可以请求特定的认证和加密机制。然而,此时移动设备尚未拥有安全通信所需的加密密钥。

与其他安全方案类似,共享秘密(如密码)不会直接用作加密密钥。因此,移动设备和接入点必须基于此共享秘密协商出一个共享的对称密钥。

WPA3握手过程

目前802.11最新标准化的安全协议是WPA3。以下是WPA3的握手过程:

以下是WPA3四次握手的关键步骤:

  1. 认证服务器生成随机数N_AS,并将其发送给移动设备。双方都知道初始共享秘密(如密码)。
  2. 移动设备生成自己的随机数N_MD,并使用两个随机数(N_AS, N_MD)和初始共享秘密,生成一个对称的共享会话密钥 K_M_AP
  3. 移动设备将所有信息通过加密签名值发送回认证服务器。
  4. 认证服务器以与移动设备相同的方式,独立推导出相同的对称共享会话密钥 K_M_AP

核心概念:密钥 K_M_AP 从未在空气中传输。双方从相同的基本元素中独立推导得出,确保了密钥的安全性。

握手过程还包含随机数以防止重放攻击,并包含密码学哈希以确保消息完整性。所有交换都在无线域广播,攻击者容易窃听,因此这些措施必不可少。

相互认证与密钥分发

假设握手成功,移动设备和接入点能够相互认证。这是一种相互认证,对于防止建立恶意接入点(Rogue AP)的攻击至关重要。因为SSID是明文广播的,攻击者很容易创建一个与移动设备之前见过的SSID相同的恶意接入点。

相互认证完成后,认证服务器和移动设备派生出对称会话密钥。

共享密钥派生后,认证服务器必须将其提供给接入点。因为加密会话仅发生在移动设备与接入点之间,流量不会一直隧道传输到认证服务器。实际上,认证服务器可能与接入点位于同一设备中,但它们是逻辑上独立的功能,尤其在多个接入点由一个认证服务器支持的情况下,可能位于不同设备。

一旦移动设备和接入点都拥有共享会话密钥 K_M_AP,加密通信即可开始。

扩展认证协议(EAP)与RADIUS

我们提到了移动设备与接入点及认证服务器之间的通信。这段通信本身也不能以明文进行。

因此,我们使用扩展认证协议(EAP)。EAP定义了移动设备与认证服务器之间(通过接入点)的端到端请求-响应协议。

在无线侧,EAP over LAN(EAPoL)运行在802.11之上。而在接入点与认证服务器之间,则使用RADIUS协议。因此,接入点通过RADIUS与认证服务器通信,认证服务器也常被称为RADIUS服务器。

总结

本节课中我们一起学习了无线局域网(802.11/Wi-Fi)的安全机制。我们探讨了从基本关联到安全认证的必要性,详细分析了WPA3协议的握手过程,理解了对称会话密钥 K_M_AP 如何在不经空中传输的情况下被双方独立推导。我们还介绍了相互认证的重要性以及EAP和RADIUS协议在端到端安全认证中所扮演的角色。这些机制共同构成了保护Wi-Fi网络免受窃听和中间人攻击的基础。

在下一个视频中,我们将探讨蜂窝网络(4G/5G)中的安全。

8.8:蜂窝网络(4G/5G)中的认证与密钥交换 🔐

在本节课中,我们将学习蜂窝网络(特别是4G和5G)中的安全机制,重点关注移动设备如何安全地接入网络并进行认证与密钥交换。

在上一章中,我们初步了解了蜂窝网络中的认证过程,但并未涉及加密方面。本节我们将深入探讨这一完整的安全流程。

蜂窝网络安全概述 📡

与Wi-Fi场景不同,蜂窝网络中的移动设备配备了一张SIM卡。这张卡提供了一个全球唯一的身份标识,并包含了与运营商共享的密钥。正确认证移动设备的一个关键驱动力是,运营商需要将其与用户付费的服务套餐进行匹配,并提供相应的付费服务。

4G LTE 认证与密钥交换流程

以下是4G网络中移动设备接入和认证的核心步骤。

初始接入与认证请求

移动设备首先连接到基站,该请求被转发给拜访网络中的移动性管理实体。

  1. 移动性管理实体 生成一个认证请求,其中包含设备的国际移动用户识别码以及拜访网络的信息。
  2. 该请求被发送到归属用户服务器。MME根据IMSI号码(存储在全局数据库中)知道应该连接哪个归属网络。
  3. 归属用户服务器 决定是否授权此连接。这包括验证认证信息的有效性,以及检查用户套餐是否允许在此拜访网络中漫游。

密钥派生与令牌传递

HSS知晓移动设备SIM卡上的预共享密钥,并使用它来派生出认证令牌和期望的认证响应。

  1. HSS将认证令牌、响应令牌以及会话密钥发送回MME。
  2. 重要:HSS不会将初始的共享密钥发送给MME。拜访网络不被信任到与归属网络相同的级别。
  3. 认证令牌使用初始共享密钥加密,因此移动设备能够验证它确实来自归属网络。

移动设备验证与会话建立

此时,移动设备间接认证了网络,因为它确认拜访网络能够从归属网络获得有效的认证令牌。

  1. 移动设备生成认证响应,并将其发送回拜访网络。
  2. 拜访网络根据HSS之前提供的期望响应来验证此认证响应。
  3. 验证成功后,移动设备在拜访网络中得到认证。
  4. 拜访网络为基站生成会话密钥,移动设备也执行密钥派生。
  5. 至此,无线信道拥有了一个共享的对称密钥,可用于AES协议进行加密通信。

从4G到5G的安全演进 🚀

上一节我们介绍了4G的安全流程,本节我们来看看5G带来的关键改进。

从4G演进到5G,安全机制发生了重要变化:

  • 认证决策权:在4G中,拜访网络的MME做出认证决策;而在5G中,归属网络提供最终的认证决策(尽管MME仍参与并可拒绝认证)。
  • 物联网设备密钥:对于物联网设备,5G中不再预先共享密钥。
  • 隐私增强:4G中存在一个主要的隐私问题:设备以明文形式向基站传输其IMSI号码,这使得设备可被长期跟踪。5G通过使用公钥密码学在初始交换中加密IMSI号码,解决了这一限制。

总结与展望

本节课中,我们一起学习了蜂窝网络(4G和5G)中认证与密钥交换的基本流程。我们了解了移动设备如何通过SIM卡中的预共享密钥,在归属网络的协助下,安全地接入拜访网络并建立加密会话。同时,我们也看到了5G在增强隐私和调整密钥管理方面所做的改进。

无线与移动网络的安全是一个持续演进的领域,了解从1G到5G的安全发展史有助于理解当前设计的考量。在接下来的课程中,我们将转向操作安全领域,探讨防火墙和入侵检测系统。

8.9:防火墙与入侵检测系统 (IDS) 🔒

在本节课中,我们将学习操作安全的核心组件:防火墙和入侵检测系统。我们将探讨它们如何作为“中间盒”在网络中工作,以隔离可信的内部网络与不可信的公共互联网,并识别和阻止恶意流量。


防火墙概述 🛡️

防火墙是一种中间盒设备,用于将组织内部网络与更大的公共互联网隔离开来。它决定哪些数据包可以通过,哪些应该被阻止。通常,防火墙内的网络被认为是可信的,而防火墙外的则被认为是不可信的。

上一节我们介绍了防火墙的基本概念,本节中我们来看看防火墙旨在防御哪些攻击。

以下是防火墙试图防止的一些常见攻击:

  • 拒绝服务攻击:攻击者发送大量SYN消息或其他旨在耗尽受害者主机资源的消息。
  • 非法访问内部数据:保护某种形式的知识产权。
  • 篡改公司对外形象:黑客试图替换网页部分内容,以达到污损或恶意利用的目的。

我们可以将防火墙分为三类,它们大致按复杂度递增排列:

  1. 无状态包过滤器
  2. 有状态包过滤器
  3. 应用网关

随着列表向下,防火墙机制变得更复杂、更消耗CPU,也可能对网络性能产生更大影响。


无状态包过滤器 📦

我们的第一个案例是无状态包过滤器。这种防火墙对数据包逐一应用规则,仅根据单个数据包的属性来决定转发或丢弃。

以下是其检查的字段示例:

  • 源IP地址和目标IP地址
  • TCP和UDP的源端口和目标端口号
  • ICMP消息类型
  • TCP标志位

这是最原始的防火墙类型。虽然它能捕获许多问题并阻止未经授权的流量,但它也有无法做到的事情,我们将在研究更复杂的类型时看到。

例如,防火墙可能配置一条规则,阻止使用TCP源或目标端口23的传入和传出数据报。端口23是Telnet,许多组织会阻止Telnet,因为用户名和密码以明文传输。

另一条规则可能阻止IP协议字段为17的数据报,即UDP协议。当然,使用UDP的最常见应用是DNS,因此这会阻止网络内部用户访问外部DNS服务器。

另一条示例规则可能是阻止ACK位等于0的传入TCP段,旨在防止外部客户端与内部客户端建立TCP连接。但由于现代操作系统会随机化初始序列号,这条规则可能效果不佳。


无状态包过滤器规则示例 📝

以下是更多我们可能使用的规则示例:

如果我们的策略是禁止外部网络访问,那么可以丢弃所有发往TCP端口80的数据包。当然,许多网站使用端口443的HTTPS,因此也必须丢弃这些。

如果我们想阻止传入的TCP新连接建立,但允许发往特定Web服务器的连接,可以有一条规则:丢弃所有传入的TCP SYN包,除了发往特定Web服务器IP地址和端口号的。

我们可能希望通过阻止UDP数据包来屏蔽网络广播,尽管大多数流媒体已迁移到HTTP上运行。在这种情况下,如果我们仍想允许DNS,就必须明确允许它。

另一项策略可能是防止机构网络被用作Smurf DoS攻击的一部分,这可以通过丢弃所有发往广播地址的ICMP数据包来实现。

最后一个示例是阻止Traceroute,这可以通过丢弃所有传出的ICMP TTL过期消息来实现。


访问控制列表 (ACL) 📋

这些规则通常以表格形式实现,称为访问控制列表。ACL规则按顺序应用,第一个匹配的规则将被应用于该数据包,数据包不会看到表的其余部分。

例如,我们允许源地址在内部网络、协议为TCP、源端口为临时端口、目标端口为80的数据包通过,这些是外发的Web流量。

然后,我们也必须允许传入的Web流量(不是新连接,而是对我们外发连接的响应)。这条规则看起来非常相似但方向相反:它允许网络外部的源地址联系网络内部的目标地址,协议为TCP,源端口为80(来自Web服务器),目标端口为临时端口,并且设置了ACK标志。

我们还允许UDP端口53的流量,即DNS请求和响应。

然后,我们拒绝其他所有流量。因此,ACL底部通常有一条明确的拒绝规则。


有状态包过滤器 🔄

现在我们来看看有状态包过滤器的局限性。主要在于无状态工具不够复杂,因此仍可能有不符合逻辑的数据包通过此规则集。例如,我们允许这些ACK包通过,但可能没有对应的已建立连接。

有状态包过滤器会跟踪通过它的每个TCP连接的状态。它知道连接何时建立、何时拆除,因此可以决定何时从跟踪状态中移除这些连接。它知道连接是传入还是传出的。

因此,如果一个TCP数据包出现,它不匹配任何现有会话,也不是新的连接建立请求,那么即使它原本匹配某条规则并被允许,防火墙也可以丢弃这些数据包。

有状态包过滤器还可以使非活动连接超时。即使没有发生明确的FIN,一端或另一端的主机可能已消失,防火墙可以将其从表中移除,并不再允许数据包发往它们。

当然,如果超时设置过于激进,导致长TCP会话被防火墙中断,可能会给网络带来很多问题。


有状态ACL示例 🔍

现在,在我们的有状态包过滤器ACL列表中,我们有相同的规则集。但在允许某些数据包之前,我们会检查连接是否存在。

在我们的第一条规则中,我们明确允许SYN请求通过,因此不需要现有连接。然而,在第二条规则中,我们只允许ACK包通过,而不是任何随机数据包,因此这些数据包应匹配现有连接。我们将在第二条规则上进行检查。

同样,在第三条规则中,我们允许初始DNS请求发出,但返回的响应应匹配由外发请求建立的现有会话。如果不匹配,我们将不允许这些数据包进入。


应用网关 🚪

现在,我们来到最复杂的版本:应用网关。我们可以将有状态包过滤器视为在传输层操作,它理解端到端的流以及数据包应属于的关联。

应用网关则上升到应用层本身,它理解特定应用程序的工作原理,并根据这些应用层协议的规则决定应允许或阻止什么。

在这个示例中,我们希望允许一些用户Telnet到外部。因此,它将要求所有Telnet用户通过网关进行Telnet,而不是直接Telnet到他们的外部地址(这将被防火墙阻止)。用户必须通过网关连接,如果用户获得授权,网关会建立到目标主机的Telnet连接。

从TCP的角度来看,这个应用网关始终位于连接的中间。主机与应用程序网关建立TCP会话,而应用程序网关与最终目的地建立新的TCP会话。顺便说一句,这个应用网关必须被允许通过防火墙才能到达目的地。

路由器会阻止所有不是来自网关的Telnet连接,这简化了其规则集。


防火墙与网关的局限性 ⚠️

在处理防火墙和网关时,我们有一些局限性。

第一是IP欺骗。IP地址没有任何验证,因此互联网上甚至本地网络上的许多实体可以更改源IP地址为其他人的地址并发送数据包。

应用网关的另一个局限性是,每个需要特殊处理的应用程序都需要一个对应的网关。用户很难采用需要通过防火墙的新应用程序。甚至应用网关的创建可能远远落后于特定应用程序本身的流行。

此外,该特定应用程序的客户端软件必须能够配置为与中间网关通信,网关不是透明的。

与往常一样,所需的安全程度与施加给网络上主机的可用性和不便性之间存在权衡。即使有了所有这些机制,许多高度受保护的站点仍然会遭受通过其他途径的攻击。


入侵检测系统 (IDS) 👁️

现在我们转向入侵检测系统。我们注意到这些系统有一个更高级的版本,称为入侵防御系统。

一般来说,IDS或IPS基于深度包检测工作。它检查数据包内容,而不仅仅是报头中的几个字段,并且可以根据各种事物检查这些内容。

例如,已知的病毒签名或已知的攻击字符串(导致溢出或SQL注入攻击等)。它可以忽略这个数据包声称要发往哪个端口、属于哪个应用程序,而直接判断其中是否有任何内容看起来像已知的恶意内容。

它还可以查看多个数据包的序列以寻找关联,甚至进行重组。一些攻击者可能更复杂,将攻击分散在多个数据包中,IDS可以在查找其签名之前将这些数据包重新组合。

其他类型的关联包括端口扫描(发往特定目的地的一系列数据包,尝试大量不同端口,这不是合法应用程序的典型行为)或网络映射(看起来像Traceroute的数据包,无论是传入还是生成大量传出的TTL过期消息)。

或者拒绝服务攻击,其中来自许多不同源地址(无论是伪造的还是其他)的数据包都发往单个受害者IP地址。


非军事区 (DMZ) 与IDS部署 🏝️

我们在这里还要提到非军事区。组织通常将任何需要从外部访问的服务器放在与其内部网络分开的单独网络中。由于这些机器因外部访问而更脆弱,这有助于防止它们在遭到入侵时被用来攻击内部网络。

IDS传感器可能与防火墙放在一起,但也可以放置在网络周围的多个有利位置。通常应位于DMZ和内部网络之间,以检测任一位置的入侵。

然而,我们很可能不希望将IDS放在防火墙外部,因为那样IDS将不得不处理许多可能被防火墙阻止的攻击,而用无状态或有状态包过滤器阻止这些攻击在计算上要便宜得多。


总结 📚

我们将IDS保持在防火墙后面。这为我们网络安全章节的学习画上了句号。

我们首先研究了基本技术,包括密码学(对称和公钥密码学)、消息完整性和端点认证的概念。然后我们看到了这些技术的许多应用,当然这些并非全部应用,但包括安全电子邮件、用于HTTPS和其他端到端加密TCP连接的TLS、常用于VPN的IPsec,并简要介绍了无线安全,了解了802.11以及4G和5G蜂窝网络如何协商加密。

最后,我们以防火墙和入侵检测系统这些中间盒安全机制作为结束。

本节课中,我们一起学习了操作安全的核心——防火墙和入侵检测系统。我们探讨了从简单的无状态包过滤到复杂的应用网关等多种防火墙类型,了解了它们的工作原理、规则配置及各自的局限性。同时,我们也认识了入侵检测系统如何通过深度包检测来识别复杂攻击,并了解了DMZ在网络架构中的安全意义。这些知识是构建安全网络环境的重要基石。

9.1:多媒体网络概述

在本节课中,我们将要学习多媒体网络的基础知识。多媒体网络涉及音频、视频等连续媒体数据在互联网上的传输,是支撑流媒体、视频会议、在线游戏等现代应用的核心技术。我们将从基本概念开始,逐步了解其应用类型和面临的挑战。

多媒体音频基础

上一节我们介绍了课程概述,本节中我们来看看多媒体音频的基本原理。

多媒体是指包含音频和视频信号的内容。这些内容需要通过互联网进行流式传输,例如IP电话、远程会议、在线游戏和虚拟世界等。这些应用通常是连续性的,也称为连续媒体应用。

音频信号是模拟信号。我们可以用时间作为X轴,音频信号的振幅作为Y轴来表示它。为了在互联网上传输,需要将模拟信号转换为数字形式。

转换过程主要涉及两个步骤:采样和量化。

  • 采样:以固定频率测量模拟信号的值。例如,电话音频的采样率为每秒8000次。
  • 量化:将每个采样值四舍五入到最接近的离散级别。如果用8位二进制数表示,则有 2^8 = 256 个可能的量化值。

公式:音频比特率 = 采样率 × 量化位数
例如,电话音频:8000 样本/秒 × 8 比特/样本 = 64000 比特/秒 (64 kbps)

接收方可以将接收到的比特流转换回模拟信号进行播放,但这个过程可能会损失一些音质。

多媒体视频基础

了解了音频之后,我们来看看多媒体视频是如何表示的。

视频是一系列以恒定速率显示的图像,例如每秒24帧。每一幅数字图像由一个像素阵列构成,每个像素用若干字节表示。

为了减少传输所需的数据量,视频会进行压缩编码。编码主要利用两种冗余信息:

  1. 空间编码:压缩单帧图像内的冗余。例如,连续多个相同颜色的像素可以被编码为“颜色值”和“重复次数”。
  2. 时间编码:压缩连续帧之间的冗余。例如,只传输当前帧与上一帧之间的差异部分。

视频编码的速率可以是固定的,称为恒定比特率(CBR),也可以是变化的,称为可变比特率(VBR)。

多媒体网络应用类型

掌握了音频和视频的基本概念后,我们来看看多媒体在网络中的三种主要应用类型。

以下是三种主要的多媒体网络应用:

  1. 流式存储音频/视频:客户端从服务器请求已录制好的音频或视频文件(如点播电影)。服务器通过套接字连接传输数据。用户可以进行暂停、快进等交互操作。
  2. 实时交互式音频/视频:支持人与人之间的实时对话,如网络电话(VoIP)和视频会议(如Skype, Zoom)。这类应用对延迟非常敏感。
  3. 流式直播音频/视频:类似于传统的广播和电视,内容通过互联网实时传输给大量用户。通常使用IP组播技术来高效地向多个客户端分发相同内容。

流式存储视频的挑战

在流式存储视频应用中,我们面临几个关键挑战。

第一个挑战是连续播放约束。一旦客户端开始播放,播放过程必须与原始录制的时间线匹配。然而,网络延迟(或称抖动)可能导致数据包到达时间不一致。为了解决这个问题,客户端需要使用缓冲区来平滑延迟波动。

第二个挑战是客户端交互性。用户希望实现快进、跳转等操作。这需要服务器能够响应这些请求并快速定位和发送相应的视频数据段。

第三个挑战是数据包丢失。在网络传输中,视频数据包可能丢失。根据使用的传输协议(如TCP或UDP),可能会进行重传,但这可能增加延迟。

客户端缓冲与播放延迟

为了应对网络抖动,流媒体系统采用了客户端缓冲机制。

客户端会预先从服务器接收并存储一部分视频数据到缓冲区中,然后再开始播放。设服务器发送速率为 ( x(t) ),客户端播放速率为恒定值 ( R ),缓冲区填充水平为 ( Q(t) )。

核心机制:如果平均接收速率 ( \bar{x} ) 大于播放速率 ( R ),缓冲区会逐渐填充,可以抵御后续的网络延迟。如果 ( \bar{x} ) 小于 ( R ),缓冲区可能会被耗尽,导致视频播放卡顿。

因此,需要设置一个合适的初始播放延迟(即开始填充缓冲区到开始播放之间的时间),以降低缓冲区耗尽的风险。

基于UDP与TCP的流式传输

流媒体可以通过不同的传输层协议实现,主要是UDP和TCP。

以下是两种协议的对比:

  • 基于UDP的流式传输
    • 服务器可以以恒定的编码速率发送数据,有助于消除抖动。
    • 通常使用RTP/RTCP等实时协议来承载多媒体数据和控制信息。
    • 缺点:UDP可能被防火墙阻止;本身不提供可靠传输和拥塞控制,需在应用层处理。
  • 基于TCP的流式传输(如HTTP流)
    • 使用HTTP GET请求获取视频文件。TCP提供可靠、按序的数据交付。
    • 优点:易于通过防火墙;利用TCP的拥塞控制可以公平共享网络带宽。
    • 缺点:TCP的发送速率会因拥塞控制而波动,可能导致更大的播放延迟;重传机制可能不适合对延迟极其敏感的实时数据。

本节课中我们一起学习了多媒体网络的基础知识。我们从多媒体音频和视频的数字化原理出发,介绍了采样、量化和压缩编码的概念。接着,我们探讨了三种主要的多媒体网络应用:流式存储、实时交互和流式直播。我们深入分析了流式存储视频面临的挑战,特别是网络抖动和连续播放问题,并解释了客户端缓冲如何通过引入初始延迟来解决这些问题。最后,我们比较了基于UDP和TCP的流媒体传输方式的优缺点。下一节课,我们将继续学习实时交互式应用的核心——IP语音(VoIP)技术。

9.2:VoIP 语音网络

概述

在本节课中,我们将学习多媒体网络中的一个重要主题——VoIP。我们将了解VoIP的基本概念、工作原理、关键特性以及相关的服务质量问题,例如延迟、丢包和恢复机制。


什么是VoIP?

VoIP是“Voice over Internet Protocol”的缩写,即互联网协议语音。它指的是通过互联网连接提供电话服务。这意味着用户可以使用互联网连接来拨打电话,而无需依赖传统的本地电话线路。


VoIP的特点与应用

以下是VoIP的一些核心特点和应用场景:

  • 低成本:与传统电话服务相比,VoIP通常能提供更低的通话费率。
  • 功能增强:VoIP支持视频通话等高级功能。
  • 服务差异:VoIP可能不提供传统电话中的某些紧急服务(如911),但许多VoIP服务商会通过其他方式提供类似服务。
  • 连接要求:VoIP服务需要稳定的互联网连接和足够的带宽。

VoIP的工作原理

上一节我们介绍了VoIP是什么,本节中我们来看看它是如何工作的。VoIP的工作流程主要涉及信号转换和数据传输。

  1. 信号转换:VoIP首先将模拟语音信号转换为数字信号。
  2. 数据分包:数字信号被分割成数据块(chunk),每个数据块会添加应用层头部信息。
  3. 网络传输:封装好的数据通过UDP或TCP段,在应用层进行传输。通常,每个数据段会以20毫秒的间隔发送。

关键公式:每个数据块的大小计算如下:
数据大小 = 20毫秒 * 8 kbps = 160字节
这意味着每20毫秒会发送160字节的语音数据。


服务质量挑战:延迟与丢包

在IP网络上传输实时语音数据会面临服务质量挑战,主要包括网络延迟和数据包丢失。

以下是几种主要的丢包类型:

  • 网络丢包:由于网络拥塞或路由器缓冲区溢出,导致数据包在传输过程中丢失。
  • 延迟丢包:数据包到达时间过早或过晚,错过了预定的播放截止时间,从而被视为丢失。可容忍的最大端到端延迟通常为400毫秒。
  • 丢包容忍度:语音通信可以容忍一定程度的丢包。通常,丢包率在1%到10%之间是可以接受的,超过此范围则会影响通话质量。

固定播放延迟

为了处理网络延迟(抖动),接收端会引入一个固定的播放延迟(Q)。接收端会尝试在每个数据块生成时间(t)之后的Q毫秒播放它。

计算公式
播放时间 = t + Q
如果数据包在 t + Q 之后到达,就会被视为延迟丢包。

  • Q值较大:丢包率较低,但整体延迟增加。
  • Q值较小:延迟较低,但可能无法补偿网络抖动,导致丢包。

自适应播放延迟

固定延迟策略可能不够灵活,因此我们引入了自适应播放延迟。其目标是在低播放延迟和低丢包率之间取得平衡

实现自适应播放延迟的核心是动态估计网络延迟,并据此调整播放时间点。以下是两种主要的估计算法:

  1. 延迟估计(指数加权移动平均 - EWMA)
    用于估计第i个数据包的延迟。
    d_i = (1 - α) * d_{i-1} + α * (r_i - t_i)
    其中,d_i是估计延迟,α是常数(如0.1),r_i是第i个包的实际接收时间,t_i是第i个包的发送时间戳。

  2. 延迟偏差估计
    用于估计延迟的变化程度。
    v_i = (1 - β) * v_{i-1} + β * |d_i - (r_i - t_i)|
    其中,v_i是延迟偏差,β是常数。

最终播放时间计算
播放时间_i = t_i + d_i + K * v_i
其中,K是一个常数因子,用于根据网络状况调整安全边界。


丢包恢复机制

当发生丢包时,VoIP会采用一些机制来恢复或掩盖丢失的数据,以维持可接受的语音质量。由于实时性要求,重传通常不适用。

以下是两种主要的丢包恢复方案:

  • 前向纠错(FEC)

    • 原理:发送端在原始数据流之外,额外发送包含纠错信息的冗余数据包。
    • 工作方式:例如,每发送n个原始数据块,就发送一个由这n个块通过异或(XOR)运算得到的冗余块。如果这n个块中任何一个丢失,接收端可以利用冗余块和其他n-1个块重建出丢失的块。
    • 特点:增加了带宽开销(额外发送冗余数据),但可以无需重传即可恢复丢失。
  • 交织(Interleaving)

    • 原理:发送端在传输前,将语音数据单元的顺序打乱(交织)后再发送。
    • 工作方式:接收端收到后,再进行解交织,恢复原始顺序。这样,网络中连续丢失的数据包,在解交织后会分散到语音流的不同位置,形成孤立的丢失点,更容易被接收端的错误隐藏算法处理。
    • 特点:不增加带宽开销,但会引入额外的处理延迟。

示例:Skype的架构

Skype是一个典型的VoIP应用,它采用混合对等网络(P2P)架构。

  • 普通节点(Skype Client):普通用户客户端。
  • 超级节点(Super Node):拥有公网IP地址、性能较好的Skype客户端,承担中继和协助NAT穿透的角色。
  • 登录服务器:中心化的服务器,用于用户认证和上线。
  • 工作原理
    1. 客户端启动后,联系登录服务器进行认证。
    2. 登录成功后,客户端从服务器获取一个超级节点列表并与之连接,加入Skype覆盖网络。
    3. 当用户A呼叫用户B时,系统会尝试建立直接的P2P连接。
    4. 如果双方都在NAT或防火墙之后,无法直接连接,则会通过一个或多个超级节点进行中继通信。

总结

本节课中,我们一起学习了VoIP技术。我们从VoIP的基本定义和特点入手,深入探讨了其将模拟语音转换为数字数据包进行传输的工作原理。我们重点分析了VoIP面临的服务质量挑战,特别是网络延迟和丢包问题,并学习了通过固定播放延迟自适应播放延迟策略来管理延迟。接着,我们探讨了用于掩盖丢包影响的前向纠错(FEC)交织(Interleaving)恢复机制。最后,我们以Skype为例,了解了实际VoIP应用可能采用的P2P网络架构。理解这些概念对于掌握实时多媒体网络应用至关重要。

9.3:实时传输协议(RTP)与会话发起协议(SIP)

在本节课中,我们将学习多媒体网络中的两个关键协议:实时传输协议(RTP)和会话发起协议(SIP)。我们将了解它们如何支持实时音视频应用,例如视频会议和互联网电话。

概述:实时应用协议

上一节我们介绍了多媒体网络的基础概念,本节中我们来看看专门为实时通信设计的协议。实时应用对数据传输的及时性有严格要求,因此需要特殊的协议来处理音视频数据的打包、传输和控制。

实时传输协议(RTP)

RTP是一个互联网协议,用于管理多媒体数据(如音频和视频)在单播、组播或广播网络服务上的实时传输。它由互联网工程任务组(IETF)在RFC 3550中定义,主要用于音视频传输,支持视频会议等多目的地应用。

需要注意的是,RTP本身不保证数据的实时交付。因为它通常封装在UDP数据报中传输,其交付的及时性依赖于底层网络的特性。RTP的主要工作是在端系统(源和目的地)之间运行,监控数据传输,并尽力提供最佳性能。

以下是RTP的核心功能组件:

  • 载荷类型标识:标识数据包中音频或视频的编码格式(如PCM、GSM)。
  • 序列号:用于检测数据包丢失,每个RTP包都有一个16位的序列号。
  • 时间戳:反映数据的采样时刻,帮助接收方在正确的时间播放,它是一个32位的值。
  • 同步源标识符(SSRC):唯一标识RTP流中的源,长度为32位。

RTP数据包的结构封装在UDP段中。例如,发送64 kbps的PCM编码语音时,应用每20毫秒收集一个编码后的数据块(160字节),加上RTP头部,形成RTP包,再封装进UDP段进行传输。

RTP与服务质量(QoS)

RTP可以包含服务质量反馈信息,例如数据包丢失比例、往返时间、延迟抖动等。发送方可以根据这些反馈调整数据传输速率。然而,由于RTP在端系统实现,中间路由器通常不为其提供特殊处理,因此QoS的保证是有限的。

实时传输控制协议(RTCP)

RTCP是RTP的配套控制协议。它不传输媒体数据本身,而是定期发送控制包,提供会话中媒体传输质量的反馈。

以下是RTCP的主要数据包类型:

  • 发送方报告包:包含当前时间、已发送数据包和字节数等信息。
  • 接收方报告包:包含数据包丢失比例、收到的最高序列号、延迟抖动等信息。
  • 源描述包:包含发送方的电子邮件、姓名等信息,用于将SSRC映射到用户。

RTCP使用单独的组播地址和端口号,其流量通常被限制为会话总带宽的5%。其中,75%的RTCP带宽分配给接收方,25%分配给发送方,以确保在大型会议中控制信令开销。

RTP流同步

在一个RTP会话中(如视频会议),音频和视频是独立的流,拥有各自的时间戳序列。RTCP发送方报告包包含了RTP时间戳与“挂钟时间”的映射关系。接收方利用这个信息,可以对音频和视频流进行同步播放。

会话发起协议(SIP)

SIP是一个应用层信令协议,用于创建、修改和终止包含视频、语音、即时消息等在内的多媒体会话。它的作用类似于传统电话系统中的呼叫建立过程,但更加灵活,基于文本,易于扩展。

SIP提供以下主要服务:

  • 用户定位:确定被叫方当前使用的终端设备(如PC、手机)的IP地址。
  • 用户可用性:判断被叫方是否愿意加入通信。
  • 用户能力协商:协商双方支持的媒体类型和编码格式。
  • 会话建立:在主叫和被叫之间建立会话参数。
  • 会话管理:在会话中进行转移、修改(如增加媒体流)或终止操作。

SIP消息通常通过UDP或TCP发送。一个典型的SIP“邀请(INVITE)”消息包含主叫和被叫的地址、会话描述(使用SDP协议)等信息。

SIP名称翻译与用户定位

SIP使用电子邮件格式的地址(如 bob@domain.com)来标识用户。用户的实际位置(IP地址、设备)可能随时变化。SIP通过注册机制来维护这种映射关系:用户启动SIP客户端时,会向所属域的 SIP注册服务器 发送 REGISTER 消息,告知其当前地址。

SIP代理与呼叫建立

当主叫发起呼叫时,其请求首先发送到本地的 SIP代理服务器。代理服务器负责将请求路由到被叫方的SIP服务器(可能经过多个代理),最终到达被叫方的设备。响应则沿原路径返回。

总结

本节课中我们一起学习了支持实时多媒体应用的两个核心协议。

  • RTP 负责实际音视频数据的传输,提供时间戳、序列号等机制以支持有序播放和同步,其配套协议 RTCP 负责监控传输质量并提供反馈。
  • SIP 是一个信令协议,负责会话的建立、管理和终止,处理用户定位、能力协商等呼叫控制功能。

这两个协议通常协同工作:SIP用于建立会话并协商参数(如使用的端口和编码),然后媒体数据通过RTP/RTCP在已建立的会话通道上流动。理解它们的分工与协作,是掌握现代互联网实时通信技术的关键。

posted @ 2026-03-29 09:39  布客飞龙I  阅读(119)  评论(0)    收藏  举报