#计网自顶向下读书笔记
个人笔记,没有详细记录全部内容。
#计算机网络和因特网
#1.3 网络核心
网络核心由由各种路由/转发设备组成。通过路由设备将各个不同的网络进行相连,使各个端系统连接。
通过网络链路和交换机传输数据有两种基本方法:分组交换和电路交换。
#1.3.1 分组交换
在各种网络应用中、端系统彼此交换报文 。 报文能够包含协议设计者需要的任何东西。 报文可以执行一种控制功能,也可以包含数据,例如电子邮件数据、 JPEG 图像或 MP3 音频文件。
为了从源端系统向目的端系统发送一个报文,源将长报文划分为较小的数据块,称之为分组。在源和目的地之间,每个分组都通过通信链路和分组交换机传送。分组传输时会以其链路的最大传输速率通过。
交换机主要有两类,路由器和链路层交换机
1.存储转发传输
多数分组交换机在链路的输入端使用存储转发传输机制。存储转发传输是指在交换机能够开始向输出链路传输该分组的第一个比特之前,必须接收到整个分组。
2.排队时延和分组丢失
每台分组交换机与多条链路相连。对于每条相连的链路,该分组交换机具有一个输出缓存 (也称为输出队列) , 用于存储路由器准备发往那条链路的分组。该输出缓存在分组交换中起着重要的作用。
如果到达的分组需要传输到某条链路,但发现该链路正忙于传输其他分组,该到达分组必须在输出缓存中等待。因此,除了存储转发时延以外,分组还要承受输出缓存的排队时延。这些时延是变化的,变化的程度取决于网络的拥塞程度。因为缓存空间的大小是有限的,一个到达的分组可能发现该缓存已被其他等待传输的分组完全充满了。在此情况下,将出现分组丢失(即丢包),到达的分组或已经排队的分组之一将被丢弃。
3.转发表和路由选择协议
路由器从与它相连的一条通信链路得到分组,然后向与它相连的另一 条通信链路转发该分组。 但是路由器怎样决定它应当向哪条链路进行转发呢?
在因特网中,每个端系统具有一个称为IP地址的地址。当源主机要向目的端系统发送一个分组时,源在该分组的首部包含了目的地的IP地址。当一个分组到达网络中的路由器时,路由器检查该分组的目的地址的一部分,并向一台相邻路由器转发该分组。
每台路由器具有一个转发表, 用于将目的地址(或目的地址的一部分)映射成为输出链路。当某分组到达一台路由器时,路由器检查该地址,并用这个目的地址搜索其转发表,以发现适当的出链路。路由器则将分组导向该出链路。
因特网具有一些特殊的路由选择协议用于自动地设置这些转发表。 具体内容在之后的章节讨论。
#1.3.2 电路交换
在电路交换网络中,在端系统间通信会话期间,预留了端系统间沿路径通信所需要的资源(缓存,链路传输速率)。在分组交换网络中.这些资源则不是预留的。会话的报文按需使用这些资源,其后果可能是不得不等待(即排队)接入通信线路。
传统的电话网络是电路交换网络的例子。考虑当一个人通过电话网向另一个人发送信息(语音或传真)时所发生的情况。在发送方能够发送信息之前,该网络必须在发送方和接收方之间建立一条连接。这是一个名副其实的连接,因为此时沿着发送方和接收方之间路径上的交换机都将为该连接维护连接状态。用电话的术语来说,该连接被称为一条电路。当网络创建这种电路时,它也在连接期间在该网络链路上预留了恒定的传输速率(表示为每条链路传输容量的一部分)既然已经为该发送方–接收方连接预留了带宽,则发送方能够以确保的恒定速率向接收方传送数据。
以下是一个例子:

考虑一台主机要经过分组交换网络(如因特网)向另一台主机发送分组所发生的情况。与使用电路交换相同,该分组经过一系列通信链路传输。 但与电路交换不同的是,该分组被发送进网络,而不预留任何链路资源之类的东西。 如果因为此时其他分组也需要经该链路进行传输而使链路之一出现拥塞,则该分组将不得不在传输链路发送侧的缓存中等待而产生时延。 因特网尽最大努力以实时方式交付分组,但它不做任何保证。
1.电路交换网络中的复用
复用是为了将链路划分为多个电路以满足多个用户数据传输的需求。如上图1-13中,每条链路被划分为4条电路,就是链路的复用。
链路中的电路是通过频分复用 (FDM) 或时分复用 (TDM)来实现的。
对于 FDM, 链路的频谱由跨越链路创建的所有连接共享。 特别是,在连接期间链路为每条连接专用一个频段。 在电话网络中,这个频段的宽度通常为4kHz (即每秒4000 周期)。毫无疑问,该频段的宽度称为带宽。 调频无线电台也使用 FDM来共享88MHz ~ 108MHz 的频谱、其中每个电台被分配 一个特定的频段。
对于一条TDM链路,时间被划分为固定期间的帧,并且每个帧又被划分为固定数量的时隙。 当网络跨越一条链路创建一条连接(电路)时,网络在每个帧中为该连接指定一个时隙, 这些时隙专门由该连接单独使用,一个时隙(在每个帧内)可用于传输该连接的数据。

2.分组交换与电路交换的对比
电路连接不适合计算机之间的通信
连接建立的时间成本较高。
计算机之间的通信具有突发性,如果使用电路交换,则浪费的资源较多(即连接建立后就是两个端系统的专用连接,即使空闲,也不能被其他的呼叫(请求)利用。
#1.4 分组交换网中的时延,丢包和吞吐量
#1.4.1 分组交换网中的时延概述
分组从一台主机(源)出发,通过一系列路由器传输,在另一台主机(目的地)中结束它的历程。 当分组从一个节点(主机或路由器)沿着这条路径到后继节点(主机或路由器),该分组在沿途的每个节点经受了几种不同类型的时延。 这些时延最为重要的是**节点处理时延 **、排队时延、发送时延(又称传输时延)和传播时延, 这些时延总体累加起来是节点总时延。
计算:
发送时延 = 数据帧长度(b) / 信道带宽(b/s)
传播时延 = 信道长度(m) / 电磁波在信道上的传播速率(m/s)
1.时延对的类型
处理时延 (nodal processing delay)
检查分组首部和决定将该分组导向何处所需要的时间是处理时延的一部分。处理时延也能够包括其他因素,如检查比特级别的差错所需要的时间,该差错出现在从上游节点向路由器A传输这些分组比特的过程中。 高速路由器的处理时延通常是微秒或更低的数量级。在这种节点处理之后,路由器将该分组引向通往路由器B链路之前的队列。
排队时延(queuing delay)
在队列中,当分组在链路上等待传输时,它经受排队时延。实际的排队时延可以是毫秒到微秒量级。
发送时延(传输时延)( transmission delay)
假定分组以先到先服务方式传输,这在分组交换网中是常见的方式。仅当所有已经到达的分组被传输后,才能传输刚到达的分组。 用L bit表示该分组的长度,用 R bps表示从路由器A到路由器B的链路传输速率。例如,对于一条10Mbps的以太网链路,速率R=10Mbps; 对于 100Mhps的以太网链路,速率R=100Mbps。 传输时延是L/R。这是将所有分组的比特推向链路(即传输,或者说发射)所需要的时间。 实际的传输时延通常在毫秒到微秒量级。
传播时延(propagation delay)
数据从该链路的起点到目的地传播所需要的时间是传播时延。该传播速率取决于该链路的物理媒体,等于或略小于光速。
#1.4.2 排队时延和丢包
1.排队时延
令a表示分组到达队列的平均速率 (a 的单位是分组/秒,即pkt/s) ,R bps是传输速率,为了简单起见,也假定所有分组都是由L bit组成的。 则比特到达队列的平均速率 是La bps。 最后,假定该队列非常大,因此它基本能容纳无限数量的比特。 比率La/R被称为流量强度。它在估计排队时延的范围方面经常起着重要的作用。
若流量强度>1, 则比特到达队列的平均速率超过从该队列传输出去的速率。在这种情况下,该队列趋向于无限增加,并且排队时延将趋向无穷大。因此,流量工程中的一条铁律是:设计系统时流量强度不能大于1。
随着流量强度接近1,平均排队时延迅速增加。该强度的少量增加将导致时延大比例增加。

2.丢包
一条链路前的队列只有有限的容量。因为该排队容量是有限的,随着流量强度接近1, 到达的分组将发现一个满的队列。由于没有地方存储这个分组,路由器将丢弃该分组。
#1.4.4计算机网络中的吞吐量
除了时延和丢包,计算机网络中另一个至关重要的性能测度是端到端吞吐量。
为了定义吞吐量,考虑从主机A到主机B跨越计算机网络传送一个大文件,在任何瞬间的瞬时吞吐量是主机B接收到该文件的速率(bps)。如果该文件由 F 比特组成, 主机B接收到所有F比特用时T秒,则文件传送的平均吞吐量是F/T bps。
对于一个链路传输,其吞吐量是瓶颈链路的传输速率,即连接两端的所有链路中,传输速率最小的链路的传输速率。
#1.5 协议层次及其服务模型
#1.5.1 分层的体系结构
1.协议分层
为了给网络协议的设计提供一个结构,网络设计者以分层的方式组织协议以及实现这些协议的网络硬件和软件,每个协议属于这些层次之一。某层向它的上一层提供的服务, 即所谓一层的服务模型 。
每层通过在该层中执行某些动作或使用直接下层的服务来提供服务。 例如,由第n层提供的服务可能包括报文从网络的 一边到另一边的可靠交付。 这可能是通过使用第n-1层的边缘到边缘的不可靠报文传送服务,加上第n层的检测和重传丢失报文的功能来实现的。
一个协议层能够用软件、硬件或两者的结合来实现。诸如 HTTP和SMTP这样的应用 层协议几乎总是在端系统中用软件实现,运输层协议也是如此。 物理层和数据链路层负责处理跨越特定链路的通信,它们通常在与给定链路相关联的网络接口卡(例如以太网 或WiFi 接口卡)中实现。 网络层经常是硬件和软件实现的混合体。
还要注意的是,一个第 n 层协议也分布在构成该网络的端系统、分组交换机和其他组件中。 这就是说,第n层协议的不同部分常常位于这些网络组件的各部分中。
协议分层具有概念化和结构化的优点。如我们看到的那样,分层提供了一种结构化方式来讨论系统组件,模块化使更新系统组件更为容易。
各层的所有协议被称为协议栈。
1.1因特网协议栈
因特网的协议栈由5个层次组成:物理层、链路层、网络层、运输层和应用层。
本书的“自顶向下”既是“以因特网协议栈的层次从上往下”的意思
![]()
- 5.应用层
应用层是网络应用程序及它们的应用层协议存留的地方。 因特网的应用层包括许多协议,例如HTTP (它提供了Web文档的请求和传送)、SMTP (它提供了电子邮件报文的传输)和FTP (它提供两个端系统之间的文件传送)。我们将看到,某些网络功能,如将像 www. ietf. org 这样对人友好的端系统名字转换为32比特的网络地址(域名解析),也是借助于特定的应用层协议即域名系统(DNS)完成的。
应用层协议分布在多个端系统上,而一个端系统中的应用程序使用协议与另一个端系统中的应用程序交换信息分组。我们把这种位于应用层的信息分组就是常常提及的报文。
- 4.运输层
因特网的运输层在应用程序端点之间传送应用层报文。在因特网中,有两种运输协议,即TCP和UDP, 利用其中的任一个都能运输应用层报文。
TCP 向它的应用程序提供了面向连接的服务。 这种服务包括了应用层报文向目的地的确保传递和流量控制(即发送方/接收方速率匹配)。TCP也将长报文划分为短报文,并提供拥塞控制机制,因此当网络拥塞时,源抑制其传输速率。
UDP协议向它的应用程序提供无连接服务。这是一种不提供不必要服务的服务,没有可靠性,没有流量控制,也没有拥塞控制。
粗略的说,TCP协议更可靠,相对资源要求也更高(数据大小,时延等)。UDP则反之。
在本书中,我们把运输层的分组称为报文段。
- 3.网络层
网络层负责将网络层分组从一台主机移动到另一 台主机,网络层分组称为数据报。在一台源主机中的运输层协议 (TCP或UDP) 向网络层递交报文段和目的地址。
网络层包括著名的网际协议IP, 该协议定义了在数据报中的各个字段以及端系统和路由器如何作用于这些字段。一个端系统的IP仅有一个,所有具有网络层的因特网组件必须运行IP。 因特网的网络层也包括决定路由的路由选择协议,它根据该路由将数据报从源传输到目的地。
尽管网络层包括了其他网际协议和一些路由选择协议,但通常把它简单地称为IP层,这反映了 IP是将因特网连接在一起的黏合剂这样的事实。
- 2.链路层
为了将分组从一个 节点(主机或路由器)移动到路径上的下一个节点,网络层必须依靠该链路层的服务。特别是在每个节点,网络层将数据报下传给链路层,链路层沿着路径将数据报传递给下一个节点。在该下一个节点,链路层将数据报上传给网络层。
由链路层提供的服务取决于应用于该链路的特定链路层协议。例如,某些协议基于链路提供可靠传递,从传输节点跨越一条链路到接收节点。
值得注意的是,这种可靠的传递 服务不同于TCP的可靠传递服务,TCP提供从一个端系统到另一个端系统的可靠交付。 链路层的例子包括以太网、 WiFi和电缆接入网的DOCSIS协议。因为数据报从源到目的地传送通常需要经过几条链路,一个数据报可能被沿途不同链路上的不同链路层协议处理。 例如,一个数据报可能被一段链路上的以太网和下一段链路上的PPP所处理。网络层将受到 来自每个不同的链路层协议的不同服务。 在本书中,我们把链路层分组称为帧。
- 1.物理层
虽然链路层的任务是将整个帧从一个网络元素移动到邻近的网络元素,而物理层的任务是将该帧中的一个个比特从一个节点移动到下一个节点。
1.2 OSI模型
OSI模型即是开放系统互连模型,其参考模型有七层:应用层、表示层、会话层、运输层、网 络层、数据链路层和物理层。
这些层次中, 5层的功能大致与它们名字类似的因特网对应层的功能相同。所以,我们来考虑OSI参考模型中附加的两个层,即表示层和会话层。表示层的作用是使通信的应用程序能够解释交换数据的含义。 这些服务包括数据压缩和数据 加密(它们是自解释的)以及数据描述(这使得应用程序不必担心在各台计算机中表示/存储的内部格式不同的问题)。会话层提供了数据交换的定界和同步功能,包括了建立检查点和恢复方案的方法。
#1.5.2 封装

上图显示了这样一条物理路径:数据从发送端系统的协议栈向下,沿着中间的链 路层交换机和路由器的协议栈上上下下,然后向上到达接收端系统的协议栈。
路由器和链路层交换机都是分组交换机,与端系统类似,路由器和链路层交换机以多层次的方式组织它们的网络硬件和软件。而路由器和链路层交换机并不实现协议栈中的所有层次。如图所示,链路层交换机实现了第一层和第二层;路由器实现了第一层到第三层。这意味着因特网路由器能够实现IP协议,而链路层交换机则不能。尽管链路层交换机不能识别IP地址,但它们能够识别第二层地址,如以太网地址。值得注意的是,主机实现了所有5个层次,这与因特网体系结构将它的复杂性放在网络边缘的观点是一致的。
上图也说明了一个重要概念:封装。在发送主机端,一个应用层报文(图中的M) 被传送给运输层。在最简单的情况下,运输层收取到报文并附上附加信息(所谓运输层首部信息,图中的Ht)该首部将被接收端的运输层使用。应用层报文和运输层首部信息一道构成了运输层报文段。 运输层报文段因此封装了应用层报文。附加的信息也许包括了下列信息:允许接收端运输层向上向适当的应用程序交付报文的信息;差错检测位信息,该信息让接收方能够判断报文中的比特是否在途中已被改变。运输层则向网络层传递该报文段,网络层增加了如源和目的端系统地址等网络层首部信息(图中的Hn)生成了网络层数据报。该数据报接下来被传递给链路层,链路层增加它自己的链路层首部信息并生成链路层帧。 所以我们看到,在每一 层,一个分组具有两种类型的字段: 首部字段(头)和有效载荷字段。 有效载荷通常是来自上一层的分组。
封装的过程能够比前面描述的更为复杂。 例如,一个大报文可能被划分为多个运输层的报文段(这些报文段每个又可能被划分为多个网络层数据报)。在接收端,则必须从其连续的数据报中重构这样一个报文段。
#1.6 面对攻击的网络
病毒
病毒是一种需要某种形式的用户交互来感染用户设备的恶意软件。
蠕虫
蠕虫是一种无须任何明显用户交互就能进入设备的恶意软件。
Dos,拒绝服务攻击
DoS攻击使得网络、 主机或其他基础设施部分不能由合法用户使用。大多数因特网DoS攻击属于下列三种类型之一:
弱点攻击
即针对对方的漏洞进行攻击
带宽洪泛
攻击者向目标主机发送大量的分组,分组数量之多使得目标的接入链路变得拥塞,使得合法的分组无法到达服务器。
连接洪泛
攻击者在目标主机中创建大量的半开或全开TCP连接,该主机因这些伪造的连接而陷入困境,并停止接受合法的连接。
下图所示的即是分布式DoS(DDoS),攻 击者控制多个源并让每个源向目标猛烈发送流量。

分组嗅探
在无线传输设备的附近放置一台被动的接收机,该接收机就能得到传输的每个分组的副本。这些分组包含了各种敏感信息,包括口令、社会保险号、商业秘密和个人信息等。记录每个流经的分组副本的被动接收机被称为分组嗅探器(wireshark就是其中之一)。
由于分组嗅探是被动的,它并不会在信道中注入其他分组,所以基本无法检测其存在。所以我们才要加密数据。
IP欺诈
具有虚假源地址的分组注入因特网的能力被称为IP哄骗, 而它只是一个用户能够冒充另一个用户的许多方式中的一种。为了解决这个问题,我们需要采用端点鉴别,即一种使我们能够确信一个报文源自我 们认为它应当来自的地方的机制(比如http请求中的remote_addr)。
#应用层
#2.1 网络应用原理
研发网络应用程序的核心是写出能够运行在不同的端系统和通过网络彼此通信的程序。
例如,在Web应用程序中,有两个互相通信的不同的程序: 一个是运行在用户主机(桌面机、膝上机、平板电脑、智能电话等) 上的浏览器程序,另一个是运行在Web服务器主机。
网络核心设备并不在应用层上起作用,而仅在较低层起作用,特别是在网络层及以下层次起作用。将应部用软件限制在端系统的方法,促进了大量的网络应用程序的迅速研发和部署(因为不用考虑下层了)。
#2.1.1 网络应用体系
当进行软件编码之前,应当对应用程序有一个宽泛的体系结构计划。应用程序的体系结构明显不同于网络的体系结构(例如在第1章中所讨论的5层因特网体系结构)。
从应用程序研发者的角度看,网络体系结构是固定的,并为应用程序提供了特定的服务集合
另外,应用体系结构由应用程序研发者设计,规定了如何在各种端系统上组织该应用程序。在选择应用程序体系结构时,应用程序研发者很可能利用现代网络应用程序中所使用的两种主流体系结构之一:客户-服务器体系结构或对等(P2P)体系结构。
- 客户-服务器体系结构
在客户-服务器体系结构中,有一个总是打开的主机,称为服务器,它服务于来自许多其他称为客户的主机。值得注意的是,客户-服务器体系结构下,客户相互之间不直接通信。
客户-服务器体系结构的另一个特征是该服务器具有固定的、周知的地址,该地址称为IP地址。
在一个客户-服务器应用中,常常会出现一台单独的服务器主机跟不上它所有客户请求的情况。例如,一个流行的社交网络站点如果仅有一台服务器来处理所有请求,将很快变得不堪重负。为此,托管大量主机的数据中心常被用于创建强大的虚拟服务器,用以满足客户需求。

- P2P体系结构
在P2P体系结构中,对位于数据中心的专用服务器有最小的(或者没有)依赖。相反,应用程序在间断连接的主机对之间使用直接通信,这些主机对被称为对等方。这些对等方并不为服务提供商所有,而是为用户的台式机和笔记本电脑所控制。因为这种对等方通信不必通过专门的服务器,该体系结构被称为对等方到对等方的。流行的P2P应用的例子是文件共享应用BitTorrent。
P2P体系结构的特性之一是其自扩展性。例如,在一个P2P文件共享应用中,尽管每个对等方都由于请求文件产生工作负载,但每个对等方通过向其他对等方分发文件也为系统整体增加服务能力。P2P体系结构也是有成本效率的,因为它通常不需要庞大的服务器基础设施和服务器带宽。然而,未来P2P应用由于高度非集中式结构,面临安全性、性能和可靠性等挑战。

#2.1.2 进程通信
在构建网络应用程序前,还需要对程序如何运行在多个端系统上以及程序之间如何相互通信有基本了解。用操作系统的术语来说,进行通信的实际上是进程而不是程序。
- 一个进程可以被认为是运行在端系统中的一个程序。
- 当多个进程运行在相同的端系统上时,它们使用进程间通信机制相互通信。
- 进程间通信的规则由端系统上的操作系统确定。
而在本书中,我们并不特别关注同一台主机上的进程间通信,而关注运行在不同端系统(可能具有不同的操作系统)上的进程间通信。
在两个不同端系统上的进程,通过跨越计算机网络交换报文而相互通信。发送进程生成并向网络中发送报文;接收进程接收这些报文并可能通过回送报文进行响应。
1.客户和服务器进程
网络应用程序由成对的进程组成,这些进程通过网络相互发送报文。
例如,在Web应用程序,一个客户浏览器进程与一个Web服务器进程交换报文。在一个P2P文件共享系统, 文件从一个对等方中的进程传输到另一个对等方中的进程。对每对通信进程,我们通常将这两个进程之一为客户,而另一个进程为服务器。对于Web而言,浏览器是一个客户进程,Web服务器是一个服务器进程。对于P2P文件共享,下载文件的对等方为客户,上载文件的对等方为服务器。
客户和服务器进程的定义如下:在一对进程之间的通信会话场景,发起通信(即在该会话开始时发起与其他进程的联系)的进程为客户进程,在会话开始时等待联系的进程为服务器进程。
2. 进程与计算机网络之间的接口
如上所述,多数应用程序由通信进程对组成,每对中的两个进程相互发送报文。从一个进程向另一个进程发送的报文必须通过下面的网络。进程通过一个称为套接字的软件接口向网络发送报文和从网络接收报文。
下图显示了两个经过因特网通信的进程之间的套接字通信(假定由该进程使用的运输层协议是TCP协议)。如该图所示,套接字是同一台主机内应用层与运输层之间的接口。由于该套接字是建立网络应用程序的可编程接口,因此套接字也称为应用程序和网络之间的应用编程接口(API)。应用程序开发者可以控制套接字在应用层端的一切,但是对该套接字的运输层端几乎没有控制权。

应用程序开发者对于运输层的控制仅限于:
- 选择运输层协议
- 可能能设定几个运输层参数,如最大缓存和最大报文段长度
3. 进程寻址
为了向特定目的地发送邮政邮件,目的地需要有一个地址。类似地,在一台主机上运行的进程为了向另一台主机上运行的进程发送分组,接收进程需要有一个地址。为了标识该接收进程,需要定义两种信息:
- 主机的地址(因特网中就是IP地址)
- 目标主机中指定接收进程的标识符
除了知道报文发送目的地的主机地址,发送进程还必须指定运行在接收主机上的接收进程。因为一般而言一台主机能够运行许多网络应用,所以这些信息是必要的。目的地端口号用于这个目的。常用的应用有固定的端口号,如Web服务器用端口号80来标识。邮件服务器进程(使用SMTP协议)用端口号25来标识。
用于所有因特网标准协议的周知端口号的列表能够在www.iana.org处找到
#2.1.3 可供应用程序使用的运输服务
包括因特网在内的很多网络提供了不止一种运输层协议。当开发一个应用时,必须选择一种可用的运输层协议。如何做出这种选择呢?最可能的方式是,通过研究这些可用的运输层协议所提供的服务,选择一个最能为你的应用需求提供恰当服务的协议。
我们大体能够从四个方面对应用程序服务要求进行分类:
- 可靠数据传输
- 吞吐量
- 定时
- 安全性
1. 可靠数据传输
分组在计算机网络中可能丢失。例如,分组能够使路由器中的缓存溢出,或者当分组中的某些比特损坏后可能被丢弃。
因此,为了支持这些应用,必须做一些工作以确保由应用程序的一端发送的数据正确并完全地交付给该应用程序的另一端。如果一个协议提供了这样的确保数据交付服务,就认为提供了可靠数据传输。
运输层协议能够潜在地向应用程序提供的一个重要服务就是进程到进程的可靠数据传输。当一个运输协议提供这种服务,发送进程只要将其数据传递进套接字,就可以完全相信该数据将能无差错地到达接收进程。
当一个运输层协议不提供可靠数据传输时,由发送进程发送的某些数据可能到达不了接收进程。这可能能被容忍丢失的应用所接受,最值得注意的是多媒体应用,如交谈式音频/视频,它能够承受一定量的数据丢失。在多媒体应用中,丢失的数据会引起播放的音频/视频出现小干扰,而不是致命的损伤。
2. 吞吐量
具有吞吐量要求的应用程序被称为带宽敏感的应用。许多当前的多媒体应用是带宽敏感的,尽管某些多媒体应用可能采用自适应编码技术对数字语音或视频以与当前可用带宽相匹配的速率进行编码。
带宽敏感的应用具有特定的吞吐量要求,而弹性应用能够根据当时可用的带宽或多或少地利用可供使用的乔吐量。电子邮件、文件传输以及Web传送都属于弹性应用。
3. 定时
运输层协议也能提供定时保证。如同具有吞吐量保证那样,定时保证能够以多种形式实现。一个保证的例子如:发送方注入套接字中的每个比特到达接收方的套接字不迟于100ms。
交互式实时应用程序对于定时有较高要求,对于非实时的应,较低的时延总比较高的时延好,但对端到端的时延没有严格的约束。
4. 安全性
运输协议能够为应用程序提供一种或多种安全性服务。例如,在发送主机中,运输协议能够加密由发送进程传输的所有数据;在接收主机中,运输协议能够在将数据交付给接收进程之前解密这些数据。这种服务将在发送和接收进程之间提供机密性,以防数据以某种方式在这两个进程之间被观察。运输协议还能提供除了机密性以外的其他安全性服务,包括数据完整性和端点鉴别等。
#2.1.4 因特网提供的运输服务
我们已经考虑了计算机网络能够提供的通用运输服务。现在我们要更为具体地考察由因特网提供的运输服务类型。因特网(更一般的是TCP/IP网)为应用程序提供两个运输层协议,即TCP和UDP。
1. TCP服务
TCP服务模型包括面向连接服务和可靠数据传输服务。当某个应用程序调用TCP作为其运输协议时,该应用程序就能获得来自TCP的这两种服务。
- 面向连接的服务:在应用层数据报文开始流动之前,TCP让客户和服务器相互交换运输层控制信息。这个所谓的握手过程提醒客户和服务器,让它们为大量分组的到来做好准备。在握手阶段后,一个TCP连接就在两个进程的套接字之间建立了。这条连接是全双工的,即连接双方的进程可以在此连接上同时进行报文收发。当应用程序结束报文发送时,必须拆除该连接。
- 可靠的数据传输服务:通信进程能够依靠TCP,无差错、按适当顺序交付所有发送的数据。当应用程序的一端将字节流传进套接字时,它能够依靠TCP将相同流交付给接收方的套接,而没有字节的丢失和冗余。
TCP还具有拥塞控制机制,这种服务不一定能直接为通信进程带来好处,但对因特网整体有利。当发送方和接收方之间的网络出现拥塞时,TCP的拥塞控制机制会抑制发送进程(客户或服务器)。
EX. TCP安全
无论TCP还是UDP都没有提供任何加密机制,这就是说发送进程传进其套接字的数据,与经网络传送到目的进程的数据相同。因此,举例来说,如果某发送进程以明文方式发送了一个口令进入它的套接字,该明文口令将经过发送方与接收方之间的所有链路传送,这就可能在任何中间链路被嗅探和发现。
因为隐私和其他安全问题对许多应用而言已经成为至关重要的问题,所以因特网界已经研制了TCP的“强化模块”,称为运输层安全(TLS)。用TLS加强后的TCP不仅能够做传统的TCP所能做的一切,而且提供了关键的进程到进程的安全性服务,包括加密、数据完整性和端点鉴别。
注意,TLS并不是因特网运输层传输协议,它只是一种对TCP的加强,这种加强是在应用层实现的。
TLS有它自己的套接字API,这类似于传统的TCP套接字API。当一个应用使用TLS时,发送进程向TLS套接字传递明文数据;发送主机中的TLS则加密该数据,并将加密的数据传递给TCP套接字。加密的数据经因特网传送到接收进程中的TCP套接字。该接收套接字将加密数据传递给TLS,由其进行解密。最后,TLS通过它的TLS套接字将明文数据传递给接收进程。
2. UDP服务
UDP是一种不提供不必要服务的轻量级运输协议,它仅提供最低限度的服务。
UDP是无连接的,因此在两个进程通信前没有握手过程。UDP提供一种不可靠数据传输服务,也就是说,当进程将一个报文发送进UDP套接字时,UDP并不保证该报文将到达接收进程。不仅如此,到达接收进程的报文也可能是乱序到达的。
UDP不包括拥塞控制机制,所以UDP的发送端可以用它选定的任何速率向其下层(网络层)注入数据。(然而,值得注意的是实际端到端吞吐量可能小于该速率,这可能是由中间链路的带宽受限或拥塞而造成的。)
3. 因特网运输协议所不提供的服务
TCP提供了可靠的端到端数据传输。并且我们也知道TCP在应用层可以很容易地用TLS来加强以提供安全服务。所以运输协议服务中的可靠数据传输和安全性都可以得到满足
今天的因特网通常能够为时间敏感应用提供满意的服务,但它不能提供任何定时或知吐量保证。
下图给出了一些流行的因特网应用所使用的运输协议。可以看到,电子邮件、远程终端访问、Web、文件传输都使用了TCP。这些应用选择TCP的最主要原因是TCP提供了可靠数据传输服务,确保所有数据最终到达目的。因为因特网电话应用(如Skype)通常能够容忍某些丢失但要求达到一定的最小速率才能有效工,所以因特网电话应用的开发者通常愿意将该应用运行在UDP上,从而设法避开TCP的拥塞控制机制和分组开销。但因为许多防火墙被配置成阻挡(大多数类型的)UDP流量,所以因特网电话应用通常被设计成如果UDP通信失败就使用TCP作为备选项。

#2.1.5 应用层协议
我们刚刚学习了通过把报文发送进套接字实现网络进程间的互相通信。那么如何构造这些报文?在这些报文中,各个字段的含义是什么?进程何时发送这些报文?这些问题将我们带进应用层协议的范围。
应用层协议(application-layer protocol)定义了运行在不同端系统上的应用程序进程如何相互传递报文。特别是应用层协议定义了以下内容:
- 交换的报文类型,例如请求报文和响应报文。
- 各种报文类型的语法,如报文中的各个字段及这些字段是如何描述的。
- 字段的语义,即这些字段中信息的含义。
- 确定一个进程何时以及如何发送报文,对报文进行响应的规则。
有些应用层协议是由RFC文档定义的,因此它们位于公共域中。例如,Web的应用层协议HTTP(超文本传输协议[RFC 7230])就作为一个RFC可供使用。如果浏览器开发者遵从HTTP RFC规则,所开发出的浏览器就能访问任何遵从该文档标准的Web服务器并获取相应Web页面。还有很多别的应用层协议是专用的,有意不为公共域所用。例如,Skype使用了专用的应用层协议。
区分网络应用和应用层协议是很重要的。应用层协议只是网络应用的一部分(尽管它是应用非常重要的一部分)。例如,Web是一种客户-服务器应用,它允许客户按照需求从Web服务器获得文档。该Web应用有很多组成部分,包括文档格式的标准(即HIML)、Web浏览器(如Chrome和Microsoft Internet Explorer)、Web服务器(如Apache、Microsoft服务器程序),以及一个应用层协议。Web的应用层协议是HITP,它定义了在浏览器和Web服务器之间传输的报文格式和序列。因此,HTTP只是Web应用的一个部分(尽管是重要部分)。
#2.2 Web和HTTP
#2.2.1 HTTP概述
Web的应用层协议是超文本传输协议(HyperText Transfer Protocol,HTTP),它是Web的核心。HTTP由两个程序实现:一个客户程序和一个服务器程序。客户程序和服务器程序运行在不同的端系统中通过交换HTTP报文进行会话。HTTP定义了这些报文的结构以及客户和服务行报文交换的方式。在详细解释HITP之前,先了解一些Web术语。
Web页面(Web page)(也叫文档)是由对象组成的。一个对象(object)只是一个文件,诸如一个HIML文件、一个JPEG图形、一个JavaScript文件、一个CCS样式表文件或一个视频片段,它们可通过一个URL寻址。多数Web页面含有一个HTML基本文件(base HTML file)以及几个引用对象。例如,如果一个Web页面包含HTML文本和5个JPEGC图形,那么这个Web页面有6个对象:一个HTML基本文件和5个图形。HTML基本文件通过对象的URL引用页面中的其他对象。每个URL由两部分组:存放对象的服务器主机和名和对象的路径。例如,一个URL为http:www.someSchool.edu/ysomeDepartment/picture.gif
,其中的www.someSchool.edu
就是主机名,/someDepartment/picture.gif
就是路径名。因为Web浏览器(Web browser)实现了HTTP的客户端,所以在Web环境中我们经常交换使用浏览器和客户这两个术语。Web服务器(Webserver)实现了HTTP的服务器端,它用于存储Web对象,每个对象由URL寻址。流行的Web服务器有Apache和Nginx等。
HTTP定义了Web客户向Web服务器请求Web页面的方式,以及服务器向客户传送Web页面的方式。我们稍后详细讨论客户和服务器的交互过程,而其基本思想在下图中进行了图示。当用户请求一个Web页面(如点击一个超链接)时浏览器向服务器发出对该页面中所包含对象的HTTP请求报文,服务器接收到请求并用包含这些对象的HTTP响应报文进行啊应。

HTTP使用TCP作为它的支撑运输协议(而不是在UDP上运行)。HTTP客户首先发起一个与服务器的TCP连接。一旦连接建立,该浏览器和服务器进程就可以通过套接字接口访问TCP。
客户向它的套接字接口发送HTTP请求报文并从它的套接字接口接收HTTP响应报文。类似,服务器从它的套接字接口接收HTTP请求报文并向它的套接字接口发送HTTP响应报文。一旦客户向它的套接字接口发送了一个请求报文,该报文就脱离了客户控制并进入TCP的控制。
TCP为HTTP提供可靠数据传输服务。这意味着,一个客户进程发出的每个HTTP请求报文最终能完整地到达服务器;类似,服务器进程发出的每个HTTP响应报文最终能完整地到达客户。这里我们看到了分层体系结构最大的优点,即HTTP不用担心数据丢失,也不关注TCP从网络的数据委失和乱序故障中恢复的细节。那是TCP以及协议栈较低层协议的工作。
需要注意:服务器向客户发送被请求的文件,而不存储任何关于该客户的状态信息。假如某个特定的客户在短短的几秒内两次请求同一个对象,服务器并不会因为刚刚为该客户提供了该对象就不再做出反应,而是重新发送该对象。因为HTTP服务器并不保存关于客户的任何信息,所以我们说HTTP是一个无状态协议(stateless protocol)。我们同时也注意到Web使用了客户服务器应用程序体系结构。Web服务器总是打开的,具有一个固定的IP地址,且它服务于可能来自数以百万计的不同浏览器的请求。
HTTP的初始版本称为HTTP/1.0,其可追溯到20世纪90年代早期[RFC1945]。到2020年为止,绝大部分的HTTP事务都采用HTTPZ1.1[RFC7230]。然而,越来越多的浏览器和Web服务器也支持新版的HTTP,称为HPTP/2.0[RFC7540]。在本节结束时,将给出HTTP/2.0的简介。
#2.2.2 非持续连接和持续链接
在许多因特网应用程序中,客户和服务器在一个相当长的时间范围内通信,在此期间,客户发出一系列请求,并且服务器对每个请求进行响应。依据应用程序以及该应用程序的使用方式,这一系列请求可以以规则的间隔周期性地或者间断性地一个接一个发出。
当每个请求/响应对是经一个单独的TCP连接发送,则该应用程序被称为使用非持续连接(non-persistentconnection)。
当所有的请求及其响应经相同的TCP连接发送,则该应用程序被称为使用持续连接(persistentconnection)。
为了深入地理解该设计问题,我们研究在特定的应用程序即HTTP的情况下持续连接的优点和缺点,HTTP既能够使用非持续连接,也能够使用持续连接。尽管HTTP默认使用持续连接,但HITP客户和服务器也能配置成使用非持续连接。
1. 采用非持续连接的HTTP
我们看看在非持续连接情况下从服务器向客户传送一个Web页面的步骤。假设该页面含有1个HTML基本文件和10个JPEG图形,并且这11个对象位于同一台服务器上。进一步假设该HTML文件的URL为http://www.example.com/index.html,以下是请求发送的情况:
- HTTP客户进程在端口号80发起一个到服务器www.example.com的TCP连接,该端口号是HTTP的默认端口。在客户和服务器上分别有一个套接字与该连接相关联。
- HTTP客户经它的套接字向该服务器发送一个HTTP请求报文。请求报文中包含了路径名/index.html。
- HTTP服务器进程经它的套接字接收该请求报文,从其存储器(通常是RAM)中检索出对象index.html(注意工作目录问题),在一个HTTP响应报文中封装对象,并通过其套接字向客户发送响应报文。
- HTTP服务器进程通知TCP断开该TCP连接。(但直到TCP确认客户得到完整的响应报文后,它才会实际中断连接。)
- HTTP客户接收响应报文,TCP连接关闭。该报文指出封装的对象是一个HTML文件,客户从响应报文中提取出该文件,检查该HTML文件,得到对10个JPEG图形的引用。
- 对每个引用的JPEG图形对象重复前4个步骤。
当浏览器收到Web页面后,向用户显示该页面。两个不同的浏览器也许会以不同的方式解释(即向用户显示)该页面。HTTP与客户如何解释一个Web页面毫无关系。HTTP规范([RFC1945]
和[RFC7540]
)仅定义了在HTTP客户程序与HTTP服务器程序之间的通信协议。
上面的步骤举例说明了非持续连接的使用,其中每个TCP连接在服务器发送一个对象后关闭,即该连接并不为其他的对象而持续下来。HTTP71.0应用了非持续TCP连接。值得注意的是每个TCP连接只传输一个请求报文和一个响应报文。因此在本例,当用户请求该Web页面时,要产生11个TCP连接。
在上面描述的步骤,我们有意没有明确客户获得这10个JPEG图形对象是使用10个串行的TCP连接,还是某些JPEG对象使用了一些并行的TCP连接。事实上,用户能够配置现代浏览器来控制连接的并行度。浏览器打开多个TCP连接,并且请求经多个连接请求某Web页面的不同部分。我们在下一章会看到,使用并行连接可以缩短响应时间。
在继续讨论之前,我们来简单估算一下从客户请求HTML基本文件起到该客户收到整个文件止所花费的时间。为此,我们给出往返时间(Round-TripTime,RTT)的定义,该时间是指一个短分组从客户到服务器然后再返回客户所花费的时间。RTT包括分组传播时延、分组在中间路由器和交换机上的排队时延以及分组处理时延。现在考虑当用户点击超链接时会发生什么现象。如下图所示,,这引起浏览器在它和Web服务器之间发起一个TCP连接;这涉及一次“三次握手”过程,即客户向服务器发送一个小TCP报文段,服务器用一个小TCP报文段做出确认和响应,最后,客户向服务器返回确认(确认连接建立)。三次握手中前两个部分所耗费的时间占一个RTT。完成了三次握手的前两个部分后,客户结合三次握手的第三部分向该TCP连接发送一个HTTP请求报文。一旦该请求报文到达服务器,服务器就在该TCP连接上发送HTML文件。该HTTP请求/响应用去了另一个RTT。因此,粗略地讲,总的响应时间就是两个RTT加上服务器传输HTML文件的时间。

非持续性连接的缺点非常明显。第一,必须为每一个请求的对象建立和维护一个全新的连接。对于每个这样的连接,在客户和服务器中都要分配TCP的缓冲区和保持TCP变量,这给Web服务器带来了严重的负担,因为一台Web服务器可能同时服务于数以百计不同客户的请求。第二,每一个对象经受两倍RTT的交付时延,即一个RTT用于创建TCP,另一个RTT用于请求和接收一个对象。
2. 采用持续连接的HTTP
在采用HTTP1.1持续连接的情况,服务器在发送响应后保持该TCP连接打开。在相同的客户与服务器之,后续的请求和响应报文能够通过相同的连接进行传送。特别是,一个完整的Web页面(上例中的HTML基本文件加上10个图形)可以用单个持续TCP连接进行传送。更有甚者,位于同一台服务器的多个Web页面在从该服务器发送给同一个客户时,可以在单个持续TCP连接上进行。对对象的这些请求可以一个接一个地发出,而不必等待对未决请求(流水线)的回答。通常,如果一条连接经过一定时间间隔(一个可配置的超时间隔)仍未被使用,HTTP服务器就关闭该连接。HTTP的默认模式是使用带流水线的持续连接。
#2.2.3 HTTP 报文格式
HTTP规范[RFC1945,RFC7230,RFC7540]包含了对HTTP报文格式的定义。HTTP报文有两种:请求报文和响应报文。下面讨论这两种报文。
1. HTTP请求报文
下面提供了一个典型的HTTP请求报文:
GET /soemedir/page.htmL HTTIP/1.1
Host: www.Someschool.edu
Connection: Close
User-agent: Mozilla/5.0
Accept-Language: fr
通过仔细观察这个简单的请求报文,我们就能学到很多东西。首先,我们看到该报文是用普通的ASCII文本书写的,这样有一定计算机知识的人都能够阅读它。其次,我们看到该报文由5行组成,每行由一个回车和换行符(/t/n
)结束。最后一行后再附加一个回车和换行符。虽然这个特定的报文仅有5行,但一个请求报文能够具有更多的行或者至少为一行。
HTTP请求报文的第一行叫作请求行(requestline),其后继的行叫作首部行(headerline)。请求行有3个字段:方法字段、URL字段和HTTP版本字段。方法字段可以取几种不同的值,包括GET、POST、HEAD、PUT和DELETE。绝大部分的HTTP请求报文使用GET方法。当浏览器请求一个对象时,使用GET方法,在URL字段带有请求对象的标识。在本例中,该HTTP报文在请求对象/somedirpage.html
。其版本字段是自解释的,在本例中,浏览器实现的是HTTP/1.1版本。
现在我们看看本例的首部行。首部行Host:www.someschool.edu
指明了的主机。你也许认为该首部行是不必要的,因为在该主机中已对象所在经有一条TCP连接存在了。但是,如我们将在2.2.5节中所见,该首部行提供的信息是Web代理高速缓存所要求的。通过包含Connection:close
首部行,该浏览吉告诉服务器不要麻烦地使用持续连接,它要求服务吉在发送完被请求的对象后就关闭这条连接。User-agent:
首部行用来指明用户代理,即向服务器发送请求的浏览器的类型。这里浏览器类型是Mozila/5.0
,即Firefox浏览器。这个首部行是有用的,因为服务器可以有效地为不同类型的用户代理实际发送相同对象的不同版本(每个版本都由相同的URL寻址)。最后,Accept-language:
首部行表示用户想得到该对象的法语版本(如果服务器中有这样的对象的话);否则,服务器应当发送它的默认版本。Accept-language:
首部行仅是HTTP中可用的众多内容协商首部之一。
看过一个例子之后,我们再来看看如下图所示的一个请求报文的通用格式。我们看到该通用格式与我们前面的例子密切对应。然而,在首部行(与附加的回车和换行符)后有一个实体体(entitybody)。使用GET方法时整个实体体为空,而使用POST方法(并不止)时才使用该实体体。当用户提交表单时,HTTP客户常常使用POST方法,例如当用户向搜索引擎提供搜索关键词时。使用POST报文时,用户仍可以向服务器请求一个Web页面,但Web页面的特定内容依赖于用户在表单字段中输入的内容。如果方法字段的值为POST,则实体体中包含的就与用户在表单字段中的输入值有关。
HTML表单将是经常使用GET方法,并在(表单字段)所请求的URL中包括输入的数据。例如,一个表单使用GET方法,它有两个字段,分别填写的是monkeys和bananas这样,该URL结构为www.somesite.com/animalsearch?monkeys&bananas
。
这里的
monkey
和bananas
就是GET Params。
HEAD方法类似于GET方法。当服务器收到一个使用HEAD方法的请求时,将会用一个HTTP报文进行响应,但是并不返回请求对象。应用程序开发者常用HEAD方法进行调试跟踪。
PUT方法常与Web发行工具联合使用,它允许用户上传对象到指定的Web服务需上指定的路径(目录)。PUT方法也被那些需要向Web服务器上传对象的应用程序使用。
DELETE方法允许用户或者应用程序删除Web服务器上的对象。
2.HTTP响应报文
下面提供了一条典型的HTTP响应报文。该响应报文可以是对刚刚讨论的例子中请求报文的响应。
HTTP/1.1 200 OK
Conriection: close
Date: Tue, 18 Aug 2015 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 18 Aug 2015 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html
(data ...)
仔细看一下这个响应报文。它有三个部:一个初始状态行(status line),6个首部行(header line),然后是实体体(entity body)。实体体部分是报文的主要部分,即它包含了所请求的对象本身(表示为data…)。
状态行有3个字段:协议版本字段、状态码和响应状态信息。在这个例子中,状态行指示服务器正在使用HTTP/1.1,并且一切正常(状态码200,即服务器已经找到并正在发送所请求的对象)。
现在来看看首部行。
Connection: close
首部行告诉客户,发送完报文后将关闭该TCP连接。Date
首部行指示服务器产生并发送该响应报文的日期和时间。值得一提的是,这个时间不是指对象创建或者最后修改的时间,而是服务器从它的文件系统中检索到该对像,将该对象插入响应报文,并发送该响应报文的时间。Server
首部行指示该报文是由一台Apache Web服务器产生的,它类似于HTTP请求报文中的User-agent
首部行。Last-Modiftied
首部行指示该对象创建或最后修改的时间与日期。“Last-Modified
首部行对既可能在本地客户也可能在网络缓存服务器(即代理服务器)上的对象缓存来说非常重要,下文将更为详细地讨论Last-Modified
首部行。Content-Length
首部行指示了被发送对象中的字节数。Content-Type
首部行指示了实体体中的对象是HTML文本。(该对象类型应该正式地用Content-Type
首部行而不是文件扩展名来指示。)Content-Length也是可以引发安全问题的,比如CVE-2024-21096。
一些常见的状态码和相关的短语包括:
- 200 OK:请求成功,信息在返回的响应报文中。
- 301 Moved Permanently:请求的对象已经被永久转移了,新的URL定义在响应报文的
Location
首部行。客户软件将自动获取新的URL。 - 400 Bad Request: 一个通用差错代码,指示该请求不能被服务器理解。
- 403 Forbidden: 拒绝访问(无权限访问或不合规范等)。
- 404 Not Found: 被请求的文档不在服务器上。
- 500 Internal Server Error: 服务器内部错误。
- 505 HTTP Version Not Supported: 服务器不支持请求报文使用的HTTP版本。
在本节中,我们讨论了HTTP请求报文和响应报文中的一些首部行。HTTP规范中定义了许许多多的首部行,这些首部行可以被浏览器、Web服务器和网络缓存服务器插入(当然也可以自己来加)。我们只提到了全部首部行中的少数几个,在2.2.5节中我们讨论网络Web缓存时还会涉及其他几个。
浏览器是如何决定在一个请求报文中包含哪些首部行的呢?Web服务器又是如何决定在一个响应报文中包含哪些首部行呢?浏览器产生的首部行与很多因素有关,包括浏览器的类型和版本、浏览器的用户配置、浏览器当前是否有一个缓存的但可能超期的对象版本。Web服务器的表现也类似:在产品、版本和配置上都有差异,所有这些都会影响响应报文中包含的首部行。
#2.2.4 用户与服务器的交互: Cookie
我们前面提到了HTTP服务器是无状态的。这简化了服务器的设计,并且允许工程师开发可以同时处理数千个TCP连接的高性能Web服务器。然而一个Web站点通常希望能够识别用户,可能是因为服务器希望限制用户的访问,或者因为它希望把内容与用户身份联系起来。为此,HTTP使用了Cookie。Cookie在[RFC 6265]中定义,它允许用户进行跟踪。目前大多数商务Web站点都使用了Cookie。
如下图所示,Cookie技术有4个组件:
在HTTP响应报文中的一个Cookie首部行;
在HTTP请求报文中的一个Cookie首部行;
在用户端系统中保留的一个Cookie文件,并由用户的浏览器进行管理;
位于Web站点的一个后端数据库。
这里省去一个例子。

Cookie可以用于标识一个用户。用户首次访问一个站点时,可能需要提供一个用户标识(可能是名字[实际上会是根据某个密钥加一些个人信息加密生成的])。在后继会话中,浏览器向服务器传递一个Cookie首部,从而向该服务器标识了用户。因此Cookie可以在无状态的HTTP之上建立一个用户会话层。例如,当用户向一个基于Web的电子邮件系统注册时,浏览需向服务器发送Cookie信息,允许该服务器在用户与应用程序会话的过程标识该用户。
尽管Cookie通常能够简化用户的因特网购物活动,但是其使用仍具有争议,因为它被认为是对用户隐私的一种侵害。如我们刚才所见,结合Cookie和用户提供的账户信息,Web站点可以得知许多有关用户的信息,并可能将这些信息卖给第三方。
所以现在很多站点会询问是否允许记录Cookie。
#2.2.5 Web缓存
Web缓存器(Webcache)也叫代理服务器(proxyserver),它是能够代表初始Web服务器来满足HTTP请求的网络实体。Web缓存器有自己的磁盘存储空间,并在存储空间中保存最近请求过的对象的副本。如下图所示,可以配置用户的浏览器,使得用户的所有HTTP请求首先指向Web缓存器[RFC 7234]。一且某浏览器被配置,每个对某对象的浏览器请求首先被定向到该Web缓存器。举例来说,假设浏览器正在请求对象http:www.someschool.edu/campus.gif,将会发生如下情况:
浏览器创建一个到Web缓存器的TCP连接,并向Web缓存HTTP请求。
Web缓存器进行检查,看看本地是否存储了该对象副本。如果有,Web绥存器就向客户浏览器用HTTP响应报文返回该对象。
如果Web绥存器中没有该对象,它就打开一个与该对象的初始服务器(即www.someschool.edu)的TCP连接。Web缓存器则在这个缓存器到服务器的TCP连接上发送一个对该对象的HTTP请求。在收到该请求后,初始服务器向该Web缓存器发送具有该对象的HTTP响应。
当Web缓存器接收到该对象时,它在本地存储空间存储一份副本,并向客户的浏览器用HTTP响应报文发送该副本(通过客户浏览器和Web缓存器之间现有的TCP连接)。

值得注意的是Web缓存器既是服务器又是客户。当它接收浏览器的请求并发回响应时,它是一个服务器。当它向初始服务器发出请求并接收响应时,它是一个客户。
在因特网上部署Web绥存器有两个原因。首先,Web缓存器可以大大减少对客户请求的响应时间,特别是当客户与初始服务器之间的瓶颈带宽远低于客户与Web缓存器之间的瓶颈带宽时更是如此。如果在客户与Web缓存器之间有一个高速连接(情况常常如此),并且如果用户所请求的对象在Web缓存器上,则Web缓存器可以迅速将该对象交付给用户。其次,如我们马上用例子说明的那样,Web缓存器能够大大减少一个机构的接入链路到因特网的通信量。通过减少通信量,该机构(如一家公司或者一所大学)就不必急于增加带宽,因此降低了费用。此外,Web缓存器能从整体上大大减少因特网上的Web流量,从而改善了所有应用的性能。
为了深刻理解缓存器带来的好处,我们考虑在下图场景下的一个例子。该图显示了两个网络,即机构(内部)网络和公共因特网的一部分。机构网络是一个高速的局域网,它的一台路由器与因特网上的一台路由器通过一条15Mbps的链路连接。这些初始服务器与因特网相连但位于全世界各地。假设对象的平均长度为1Mb,从机构内的浏览器对这些初始服务器的平均访问速率为每秒15个请求。假设HTTP请求报文小到可以忽略,因而不会在网络中以及接入链路(从机构内部路由器到因特网路由器)上产生什么通信量。我们还假设在图中从因特网接入链路一侧的路由器转发HTTP请求报文(在一个IP数据报中)开始,到它收到其响应报文(通常在多个IP数据报中)为止的时间平均为2s。我们将该持续时延非正式地称为“因特网时延”。
总的响应时间,即从浏览器请求一个对象到接收到该对象为止的时间,是局域网时延、接入时延(即两台路由器之间的时延)和因特网时延之和。我们来粗略地估算一下这个时延,局域网上的流量强度为:
(15个请求/s)x(1Mb/请求)/(100Mbps)=0.15
然而接入链路上的流量强度(从因特网路由器到机构路由器)为
(15个请求/s)x(1Mb/请求)/(15Mbps)=1
局域网上强度为0.15的通信量通常最多导致数十毫秒的时延,因此我们可以忽略局域网时延。然而,如在1.4.2节讨论的那样,如果流量强度接近1(就像图中接入链路的情况那样),链路上的时延会变得非常大并且无限增长。因此,满足请求的平均响应时间将在分钟的量级上。显然,必须想办法来改进时间响应特性。
一个可能的解决办法就是增加接入链路的速率,如从15Mbps增加到100Mbps。这可以将接入链路上的流量强度减少到0.15,这样一来,两台路由器之间的链路时延也可以忽略了。这时,总的响应时间将大约为2s,即为因特网时延。但这种解决方案也意味着该机构必须将它的接入链路由15Mbps升级为100Mbps,这是一种代价很高的方案(很贵的)。
现在来考虑另一种解决方案,即不升级链路带宽而是在机构网络中安装一个Web缓存器。这种解决方案如图2-13所示。现实中的命中率(即由一个缓存器所满足的请求的比率)通常在0.2~0.7之间。为了便于阐述,我们假设该机构的缓存命中率为0.4。因为客户和缓存连接在一个相同的高速局域网上,这样40%的请求将几乎立即会由缓存器得到响应,时延约在10ms以内。然而,剩下的60%的请求仍然要由初始服务器来满足。但是只有60%的被请求对象通过接入链路,接人链路上的流量强度从1.0减小到0.6。一般而言在15Mbps链路上,当流量强度小于0.8时对应的时延较小,约为几十毫秒。这个时延与2s因特网时延相比是微不足道的。
因此,第二种解决方案提供的响应时延甚至比第一种解决方案更低,也不需要该机构升级它到因特网的链路。该机构理所当然地要购买和安装Web缓存器。除此之外其成本较低,很多缓存器使用了运行在廉价PC上的公共域软件。
通过使用内容分发网络(Content Distribution Network,CDN),Web缓存器正在因特网中发挥着越来越重要的作用。CDN公司在因特网上安装了许多地理上分散的缓存器,因而使大量流量实现了本地化。有多个共享的CDN(例如Akamai和Limelight)和专用的CDN(例如谷歌和Netflix)。
条件GET方法
尽管高速缓存能减少用户感受到的响应时间,但也引入了一个新的问题,即存放在缓存器中的对象副本可能是陈旧的。换名话说,保存在服务器中的对象自该副本缓存在客户上以后可能已经被修改了。幸运的是,HTTP有一种机制,允许缓存器证实它的对象是最新的。这种机制就是条件GET(conditional GET)[RFC7232]。如果HTTP请求报文使用GET方法,并且请求报文中包含一个If-modified-since
首部行,那么,这个HTTP请求报文就是一个条件GET请求报文。
为了说明GET方法的操作方式,我们看一个例子。首先,一个代理缓存器(proxy cache)代表一个请求浏览器,向某Web服务器发送一个请求报文:
GET /fruit/kiwi.gif HTTP/1.1
Host: www.exotiquecuisine.com
其次,该Web服务器向缓存器发送具有被请求的对象的响应报文:
HTTP/1.1 200 OK
Date: Sat, 3 Oct 2015 15:39:29
Server: Apache/1.3.0 (Unix)
Last-Modified: Wed,9 Sep 2015 09:23:24
Content-Type: image/gif
(data...)
该缓存器在将对象转发到请求的浏览器的同时,也在本地缓存了该对象。重要的是,缓存器在存储该对象时也存储了最后修改日期。最后,一个星期后,另一个用户经过该缓存器请求同一个对象,该对象仍在这个缓存器中。由于在过去的一个星期中位于Web服务器上的该对象可能已经被修改了,该缓存器通过发送一个条件GET执行最新检查。具体来说,该缓存器发送:
GET /fruit/kiwi.gif HTTP/1.1
Host: www.exotiquecuisine,com
If-modified-since: Wed, 9 Sep 2015 09:23:24
值得注意的是If-modified-since
首部行的值正好等于一星期前服务器发送的响应报文中的Last-Modified
首部行的值。该条件GET报文告诉服务器,仅当自指定日期之后该对象被修改过,才发送该对象。假设该对象自2015年9月9日09:23:24后没有被修改。接下来的第四步,Web服务器向该缓存器发送一个响应报文:
HTTP/1.1 304 Not Modified
Date: Sat, 10 Oct 2015 15:39:29
Server: Apache/1.3.0 (Unix)
(empty entity body)
我们看到,作为对条件CET方法的响应,该Web服务器仍发送一个响应报文,但并没有在该响应报文中包含所请求的对象。包含该对象只会浪费带宽,并增加用户感受到的响应时间,特别是如果该对象很大更是如此。值得注意的是在最后的响应报文中,状态行中为304 Not Modified,它告诉缓存器可以使用该对象,能向请求的浏览器转发它(该代理缓存器)缓存的对象副本。
#2.2.6 HTTP/2
于2015年标准化的HTTP/2[RFC 7540]是自HTTP/1.1以后的首个新版本,而HTTP/1.1是1997年标准化的。HTTP/2公布后,2020年,在排名前1000万的Web站点中,超过40%的站点支持HTTP/2。大多数浏览器(包括Chrome、Internet Explorer、Safari、0pera和Firefox)也支持HITP/2。
HTTP/2的主要目标是减小感知时延,其手段是经单一TCP连接使请求与响应多路复用,提供请求优先次序和服务推送,并提供HTTP首部字段的有效压缩。HTTP/2不改变HTTP方法、状态码、URL或首部字段,而是改变数据格式化方法以及客户和服务器之间的传输方式。
回想HTTP/1.1,其使用持续TCP连接,允许经单一TCP连接将一个Web页面从服务器发送到客户。由于每个Web页面仅用一个TCP连接,服务器的套接字数量被压缩,并且所传送的每个Web页面平等共享网络带宽(如下面所讨论的)。但Web浏览器的开发者很快就发现了经单一TCP连接发送一个Web页面中的所有对象存在队首阻塞[Head Of Line (HOL) blocking]问题。
为了理解HOL阻塞,考虑一个Web页面,它包括一个HTML基本页面、靠近Web页面顶部的一个大视频片段和该视频下面的许多小对象。进一步假定在服务器和客户之间的通路上有一条低速/中速的瓶颈链路(例如一条低速的无线链路)。使用一条TCP连接,视频片段将花费很长时间来通过该瓶颈链路,与此同时,那些小对象将被延迟,因为它们在视频片段之后等待。也就是说,链路前面的视频片段阻塞了后面的小对象。HTTP/1.1浏览器解决该问题的典型方法是打开多个并行的TCP连接,从而让同一Web页面的多个对象并行地发送给浏览器。采用这种方法,小对象到达并呈现在浏览器上的速度要快得多,因此可减小用户感知时延。
TCP拥塞控制(将在第3章中详细讨论)也使得浏览器倾向于使用多条并行TCP连接而非单一持续连接。粗略来说,TCP拥塞控制针对每条共享同一条瓶颈链路的TCP连接,给出一个平等共享该链路的可用带宽。如果有n条TCP连接运行在同一条瓶颈链路上,则每条连接大约得到1/n带宽。通过打开多条并行TCP连接来传送一个Web页面,浏览器能够”欺骗”并霸占该链路的大部分人带宽。许多HTTP/1.1打开多达6条并行TCP连接并非为了避免HOL阻塞,而是为了获得更多的带宽。
HTTP/2的基本目标之一是摆脱(或至少减少其数量)传送单一Web页面时的并行TCP连接。这不仅减少了需要服务器打开与维护的套接字数量,而且允许TCP拥塞控制像设计的那样运行。但与只用一个TCP连接来传送一个Web页面相比,HTTP/2要求仔细设计相关机制以避免HOL阻塞。
1. HTTP/2 成帧
用于HOL阻塞的HTTP/2解决方案是将每个报文分成小帧,并且在相同TCP连接上交错发送请求和响应报文。为了理解这个问题,再次考虑由一个大视频片段和许多小对象(例如8个)组成的Web页面的例子。此时,服务器将从希望查看该Web页面的浏览器处接收到9个并行的请求。对于每个请求,服务器需要向浏览器发送9个相互竞争的报文。假定所有帧具有固定长度,该视频片段由1000帧(报文帧)组成,并且每个较小的对象由2帧组成。使用帧交错技术,在视频片段发送第一帧后,发送每个小对象的第一帧。然后在视频片段发送第二帧后,发送每个小对象的第二帧。因此,在发送视频片段的18帧后,所有小对象就发送完成了。如果不采用交错,则发送完其他小对象共需要发送1016帧。因此HTTP/2成帧机制能够极大地减小用户感知时延。
将一个HTTP报文分成独立的帧、交错发送它们并在接收端将其装配起来的能力,是HTTP/2最为重要的改进。这一成帧过程是通过HTTP/2协议的成帧子层来完成的。当某服务器要发送一个HTTP响应,其响应由成帧子层来处理,即将响应划分为帧。响应的首部字段成为一帧,报文体被划分为一帧以用于更多的附加帧。通过服务器中的成帧子层,该响应的帧与其他响应的帧交错并经过单一持续TCP连接发送。当这些帧到达客户时,它们先在成帧子层装配成初始的响应报文,然后像以往一样由浏览器处理。类似地,客户的HTTP请求也被划分成帧并交错发送。
除了将每个HTTP报文划分为独立的帧外,成帧子层也对这些帧进行二进制编码。二进制协议解析更为高效,会得到略小一些的帧,并且更不容易出错。
2. 响应报文的优先次序和服务器推(推送)
报文优先次序允许研发者根据用户要求安排请求的相对优先权,从而更好地优化应用的性能。如前文所述,成帧子层将报文组织为并行数据流发入相同的请求方。当某客户向服务器发送并发请求时,它能够为正在请求的响应确定优先次序,方法是为每个报文分配1到256之间的权重。较大的数字表明较高的优先。通过这些权重,服务器能够为具有最高优先权的响应发送第一帧。此外,客户也可通过指明相关的报文段ID,来说明每个报文段与其他报文段的相关性。
HTTP/2的另一个特征是允许服务器为一个客户请求而发送多个响应。即除了对初始请求的啊应外,服务器能够向该客户推额外的对象,而无须客户再进行任何请求。因为HTML基本页指示了需要在页面呈现的全部对象,所以这一点是可实现的。因此无须等待对这些对象的HTTP请求,服务器就能够分析该HTML页,识别需要的对象,并在接收到对这些对象的明确的请求前将它们发送到客户。服务器推消除了因等待这些请求而产生的额外时延。
HTTP/3
QUIC(在第3章讨论)是一种新型的“运输”协议,它在应用层中最基本的UDP之上实现。QUIC具有几个能够满足HTTP的特征,例如报文复用(交错)、每流流控和低时延连接创建。HTTP/3是一种设计在QUIC之上运行的新HTTP。到2020年为止,HTTP/3处于因特网草案阶段,还没有全面标准化。许多HTTP/2特征(如报文交错)已被收入QUIC中,使得对HTTP/3的设计更为简单合理。
#2.3 因特网中的电子邮件
自从有了因特网,电子邮件就在因特网上流行起来。当因特网还在襁褓之中时,电子邮件已经成为最流行的应用程序,年复一年,它变得越来越精细,越来越强大。它仍然是当今因特网上最重要和实用的应用程序之一。
与普通邮件一样,电子邮件是一种异步通信媒介,即人们方便时就可以发送邮件,不必与他人的计划进行协调。与普通邮件相比,电子邮件更为快速,易于分发,而且价格便宜。现代电子邮件具有许多强大的功能,包括添加附件,超链接,HTML格式文本和图片。
在本节中,我们将讨论于因特网电子邮件核心地位的应用层协议。在深入讨论这些应用层协议之前,我们先总体看看因特网电子邮件系统和他的关键组件。
图2-14给出了因特网电子邮件系统的总体情况。从该图中,我们可以看到它有3个主要组成部分:用户代理(user agent)、邮件服务器(mail server)和简单邮件传输协议〈Simple Mail Transfer Protocol,SMTP)。下面我们结合发送方Alice发电子邮件给接收方Bob的场景,对每个组成部分进行描述。用户代理允许用户阅读,恢复,转发,保存和撰写报文。微软的Outlook、Apple Mail、基于Web的Gmail和运行在智能手机上的Gmail客户端等都是电子邮件用户代理。当Alice完成邮件撰写时,她的邮件代理向其邮件服务器发送邮件,此时邮件放在邮件服务器的外出报文队列。当Bob要阅读代理在其邮件服务器的邮箱中取得该报文。
邮件服务器形成了电子邮件体系结构的核心。每个接收方(如Bob)在其中的某个邮件服务器上有一个邮箱(mail box)。Bob的邮箱管理和维护着发送给他的报文。一个典型的邮件发送过程是:从发送方的用户代理开始,传输到发送方的邮件服务器,再传输到接收方的邮件服务器,然后在这里被分发到接收方的邮箱中。当Bob要在他的邮箱中读取该报文时,包含他邮箱的邮件服务器(使用用户名和口令)鉴别其身份。Alice的邮箱也必须能处理Bob的邮件服务器的故障。如果Alice的服务器不能将邮件交付给Bob的服务器(比如Bob的邮件服务器发生了故障),Alice的邮件服务器在一个报文队列(message queue)中保持该报文并在以后尝试再次发送。通常每30分钟左右进行一次和尝试,如果几天后仍不能成功,服务器就删除该报文并以电子邮件的形式通知发送方(Alice)。

SMTP是因特网电子邮件中主要的应用层协议。它使用TCP可靠数据传输服务,从发送方的邮件服务器向接收方的邮件服务器发送邮件。像大多数应用层协议一样,SMTP也有两个部分:运行在发送方邮件服务器的客户端和运行在接收方邮件服务器的服务器端。每台邮件服务器上既运行SMTP的客户端也运行SMTP的服务器端。当一个邮件其他邮件服务器发送邮件时,它服务器向就表现为SMTP的客户;当一个邮件服务器从其他邮件服务器上接收邮件时,它就表现为SMTP的服务器。
#2.3.1 SMTP
RFC 5321给出了SMTP的定义。SMTP是因特网电子邮件的核心。如前所述,SMTP用于从发送方的邮件服务器发送报文到接收方的邮件服务器。SMTP问世的时间比HTTP要长得多(初始的SMTP的RFC可追溯到1982年,而SMTP在此之前很长一段时间就已经出现了)。尽管电子邮件应用在因特网上的独特地位可以证明SMTP有着众多非常出色的性质,但它所具有的某种陈旧特征表明它仍然是一种继承的技术。例如,它限制所有邮件报文的体部分(不只是其首部)只能采用简单的7比特ASCII表示。在20世纪80年代早期,这种限制是明智的,因为当时传输能力不足,没有人会通过电子邮件发送大的附件或大的图片、声音、视频文件然而,在今天的多媒体时代,7比特ASCII的限制的确有点痛苦,即在用SMTP传送邮件之前,需要将二进制多媒体数据编码为ASCI码,并且在使用SMTP传输后要求将相应的ASCII码邮件解码还原为多媒体数据。2.2节讲过,使用HTTP传送前不需要将多媒体数据编码为ASCI码。
为了描述SMTP的基本操作,我们观察一种常见的情景。假设Alice想给Bob发送一封简单的ASCII报文。
Alice调用她的邮件代理程序并提供Bob的邮件地址(例如bob@someschool.edu),撰写报文,然后指示用户代理发送该报文。
Alice的用户代理把报文发到她的邮件服务器,在那里该报文被放在报文队列中。
运行在Alice的邮件服务器上的SMTP客户发现了报文队列中的这个报文,它创建一个到运行在Bob的邮件服务器上的SMTP服务器的TCP连接。
在经过一些初始SMTP握手后,SMTP客户通过该TCP连接发送Alice的报文。
在Bob的邮件服务器上,SMTP的服务器接收该报文。Bob的邮件服务器然后将该报文放入Bob的邮箱中。
在Bob方便的时候,他调用用户代理阅读该报文。
需要注意,SMTP一般不使用中间邮件服务器发送邮件,即使这两个邮件服务器位于地球的两端也是这样。假设Alice的邮件服务器在中国香港,而Bob的服务器在美国圣路易斯,那么这个TCP连接也是从香港服务器到圣路易斯服务器之间的直接相连。特别是,如果Bob的邮件服务器没有开机,该报文会保留在Alice的邮件服务器上并等待进行新的尝试,这意味着邮件并不在中间的某个邮件服务器中存留。
我们现在仔细观察一下,SMTP是如何将一个报文从发送邮件服务器传送到接收邮件服务器的。首先,客户端SMTP(运行在发送邮件服务器主机上)在25号端口建立一个到服务器SMTP(运行在接收邮件服务器主机上)的TCP连接。如果服务器没有开机,客户端SMTP服务会在稍后继续尝试连接。一旦连接建立,服务器和客户执行某些应用层的握手(就像人们在相互交流前先进行自我介绍一样)。SMTP的客户和服务器在传输信息前先相互介绍。在SMTP握手的阶段,客户端SMTP指示发送方的邮件地址和接收方的邮件地址。一旦该SMTP客户和服务器彼此介绍之后,客户端SMTP服务发送该报文。SMTP能依赖TCP提供的可靠数据传输无差错地将邮件投递到接收服务器。该客户如果有另外的报文要发送到该服务器,就在该相同的TCP连接上重复这种处;否则,它指示TCP关闭连接。