计算机网络——应用层

应用层协议原理

应用层体系结构

有两种常见的应用层体系结构:客户-服务器结构和点对点结构。

  1. 客户-服务器体系结构(Client-Server architecture,C-S):存在一个(一些)具有固定的、广为人知的IP地址的常开服务器为所有提出请求的客户端服务。一台计算机往往不足以承担服务器的功能,因此配备大量主机的服务中心往往承担一个虚拟服务器的功能。在这种体系结构中,客户端与客户端之间的通信必须经过服务器。
  2. 点对点体系结构(Peer-to-Peer architecture,P2P):应用程序不使用专有的服务器,而是在主机对之间直接建立连接。这些主机称为对等方或对端(Peer)。P2P结构最重要的特性就是其自扩展性,即每个对端在使用服务的同时也在提供服务,因此服务能力会自动扩展。

有些应用程序混合使用两种架构,通常存在一个中心服务器用来共享不同对端的信息(比如BitTorrent,先用Tracker服务器追踪对等方,再建立连接)。

进程通信

对计算机而言,一个程序或应用通常对应一个进程,而端系统之间的通讯实际上就是不同进程之间的通讯。 两个在不同端系统之间的进程通过交换报文而实现通讯。

对每一对通讯的进程,我们把发起通信的进程标记为客户,而等待联系的进程标记为服务器。 尽管在点对点体系结构中,一个程序从整体上看往往既充当服务器,又充当客户端,但在任何一次进程间的会话中,我们总是能标识这两种不同的进程。

任何应用程序产生的报文必须通过某种手段发送到网络之中或从中接受报文,这种手段就是套接字(Socket,原指插座)。 套接字就是端到端系统上提供的从应用层和运输层之间的接口,在实现上其由一组操作系统提供的应用程序编程接口(API)定义并操纵。 通过这些API,应用层开发者可以选择希望使用的运输层协议并指定一部分暴露的运输层参数。

为了找到不同端系统之间的进程,我们使用两个参数:IP地址端口号

运输层服务

我们关注运输层服务的四个方面:

  1. 可靠性:是否容忍数据丢失;
  2. 吞吐量:有些应用对带宽有最低要求,而有些应用的要求非常宽松;
  3. 定时:部分应用,如游戏,对各种时延有严格的要求;
  4. 安全性:是否对数据的完整性和保密性等有要求。

主流的运输层服务1只有两种:传输控制协议(TCP)和用户数字报协议(UDP)

  1. TCP服务:面向连接的可靠传输服务。
    • 面向连接:在传输报文之前,必须先建立全双工的TCP连接。维护一个状态机。
    • 可靠传输:TCP保证报文不会丢失、不会出错且按出发的相同顺序到达。
    • 支持拥塞控制:发生网络拥塞时会限制所有TCP连接。
  2. UDP服务:仅提供最小服务。
    • 无状态、无连接。
    • 不保证可靠性和有序性。
    • 无拥塞控制。

传输层协议不提供任何对吞吐量和定时的保证。 其对安全性的保证通常是通过应用层安全套接字层(Secure Socket Layer,SSL)实现的。

这一章主要介绍应用层协议,因此不涉及过多的传输层细节。

应用层协议

HTTP

超文本传输协议(Hyper-Text Transfer Protocol,HTTP)是在互联网上传输Web页面的无状态协议,即服务器不会为HTTP会话保存任何信息。 Web页面由对象组成,而一个对象对应一个文件。 HTTP的客户端通常是浏览器,因此在Web环境中我们常常混用两者。 HTTP基于TCP协议而非UDP协议。

HTTP常用两种方式组织TCP连接:非持续连接和持续连接。

  1. 非持续连接(Non-persistent):每次请求一个文件,就新建一个TCP连接,收到文件后就关闭。
    • 为建立连接和请求文件,客户端不得不等待两个往返时间(RTT,即分组从客户出发到服务器再返回客户端所需的时间)。
    • 同时请求多个文件时,可能进行并行的TCP连接。
  2. 持续连接(Persistent):使用一个TCP连接请求不同的文件。
    • 使用单个连接时,可以进行流水线化,即客户端一次发送所有请求,然后等待结果,而不是发送一个请求,等待接收完后再发送下一个请求。

通常默认的方式为带流水线的持续连接。

HTTP报文

HTTP报文分为两种:请求报文和响应报文。

请求报文总是具有以下形式:

(方法) (URL) (版本)\n\r
(首部字段名): (字段值)\n\r
...
(首部字段名): (字段值)\n\r
\n\r
(请求实体)

第一行称为请求行,从第二行到空行位置称为首部行,空行后的内容称为实体体。 常用的方法有GETPOST,版本通常为HTTP/1.1HTTP/2.0。 常见的首部字段名包括HostConnectionUser-agent等。 对GET方法,其请求实体通常为空。

响应报文总是具有以下形式:

(版本) (状态码) (短语)\n\r
(首部字段名): (字段值)\n\r
...
(首部字段名): (字段值)\n\r
\n\r
(响应实体)

除了第一行称为响应行之外其他的称呼和请求报文一致。 短语是用来描述状态码的简短说明。

HTTP协议本身是无状态的,但是这为追踪客户端的状态带来了不利因素。 为此,引入了Cookie这一机制。 从本质上讲,Cookie就是保存在客户端的信息,这些信息是按服务器的要求设置的,通常和服务器后端数据库中的某一项关联。

考虑一个典型的场景,包含了Cookie系统的4个组件:

  1. 服务器后端在数据库中保存一个用户的数据,并产生一个标识符作为cookie;
  2. 服务器返回的响应报文的头部中通过Set-cookie要求浏览器保存一个cookie;
  3. 浏览器将cookie保存下来;
  4. 在之后发送的请求报文中,浏览器通过Cookie将保存的cookie发送给服务器。

这样,服务器收到带有cookie的请求后就能从数据库中找到对应用户的数据。

缓存、代理服务器与条件GET

缓存服务器可用于降低HTTP对吞吐量的需求。 当浏览器请求某一资源时,其并不直接把请求报文发送给资源所在的服务器,而是发送给代理服务器。 代理服务器从其缓存中检查是否保存有资源的副本,若有则直接返回,若无则继续向目标服务器发送请求。 代理服务器从目标服务器得到资源后,除了把它返回给客户之外,还把它留存在自己的缓存之中。

如果在局域网中安装一个代理服务器,则可以降低对局域网的出口带宽的需求。

内容分发网络(Content Distribution Network,CDN)是这种思想进一步发展的产物。 通过把类似的缓存服务器放置在世界各地,大量的流量都可以本地化。

现在的许多浏览器都实现了内置缓存的功能。

为了实现代理服务器,我们需要解决缓存和实际内容同步的问题。 即,如果一个文件在被缓存之后更新了,如何让代理服务器获取新的版本?

我们使用条件GET方法来实现这一点。 如果一个GET请求报文中含有If-Modified-Since首部,那么它就是一个条件GET

代理服务器在获取资源的时候,还会保存响应首部的Last-Modified字段,这个字段标识了原文件最后一次修改的时间(如果没有这个字段也可以直接使用当前系统时间)。 当代理服务器的缓存命中的时候,其并不直接返回这个文件,而是继续发送一个用修改时间填充了If-Modified-Since首部字段的条件GET。 服务器收到这个GET之后,检查自此时间后是否发生了修改,如果有则发送新文件,否则发送一个304 Not Modified的响应。 然后代理服务器可根据这个响应决定返回哪个文件。

电子邮件

SMTP

简单邮件传输协议(Simple Mail Transfer Protocol,SMTP)是当下最常见的邮件协议。 和HTTP不同,这个协议主要是推协议,即客户端主要负责推送数据,而非拉协议,即客户端主要拉取数据。

SMTP基于TCP,其工作流程如下:

  1. 首先使用邮件客户端撰写并发送邮件;
  2. 邮件客户端使用SMTP把邮件推送到发件人的邮件服务器,此时保存在服务器的出站队列中;
  3. 发件人的邮件服务器使用SMTP把邮件推送到收件人的邮件服务器,此时邮件保存在收件人的收件箱中;
  4. 收件人使用其他协议收取邮件到本地。

如果收件人的服务器因故不能接受邮件,那么发件服务器会不断尝试,直到达到一定限度并取消。 如果取消,那么原则上会向发件人的收件箱中投递一封通知。

SMTP只支持七比特的ASCII字符,其他字符(或二进制数据)必须被转义,且原则上邮件不会经过任何其他SMTP服务器中转。 为了发送多种多样的多媒体数据,需要使用多用途互联网邮件扩展(Multipurpose Internet Mail Extensions,MIME)。

正如其名,SMTP的报文格式和协议规范非常简单,参见RFC 5321。 其命令只有HELO(指定发件域名)、MAIL FROM(指定发件人)、RCPT TO(指定收件人)、DATA(开始传输数据)、QUIT(退出)五个。 DATA报文以一个只含句点.的行终结。

POP3与IMAP

我们接下来考虑最后一步拉取邮件的协议,POP3和IMAP。

第三版邮局协议(Post Office Protocol version 3, POP3)的实现甚至比SMTP还简单,可在RFC 1939中查看。 其总共只含三个步骤:授权、事务处理和更新,并且是无状态的。

在授权阶段,通过命令userpass指定用户名和密码并登录。 然后,使用list列出所有用户的邮件、使用retr取回邮件。 此后,可以使用dele删除邮件。 最后,用quit退出。

IMAP是对POP3的全面加强,其支持根据文件夹或目录管理邮件和获取部分而非全部邮件内容。 和POP3不同,IMAP是有状态的,其规范在RFC 3501中。

除了这两种之外,还可以使用基于万维网(HTTP等)的邮件发送或收取。

域名系统

域名系统(Domain Name System,DNS)负责进行域名和IP地址的转换。 虽然DNS也是应用层的服务,但是其通常并不直接由哪个应用程序执行,而是作为其他应用的基础。

DNS有两层含义:其一是指由DNS服务器组成的巨大分布式数据库,其中保存了域名和地址的关系; 其二是指一个应用层的协议,负责进行域名和地址的转换。

DNS运行在UDP上。

除了查询域名之外,DNS还提供主机别名、邮件服务器别名和负载均衡等服务。

DNS工作原理概述

使用单个服务器为所有人提供DNS服务固然简单,但是又会带来诸多不便,因此DNS实际上是一个大型的分布式数据库网络。 整个网络主要分为三层:

  1. 根域名服务器:保存所有顶级域服务器的IP地址;
  2. 顶级域服务器:简称TLD,每个顶级域名都有一个顶级域服务器,保存了更低级权威服务器的IP地址;
  3. 权威服务器:保存一个区域之内所有域名的IP地址,通常由一个组织或公司运行。

在顶级域和权威服务器之间,可能还有几层其他的服务器,可达三层之多。 比如对*.edu.cn,其顶级域为cn,次级域为edu

实际上权威服务器是个相对的概念,比如对于根域名服务器,cn这个顶级域名的权威服务器就是中国互联网络信息中心中的顶级域服务器。

除了这些服务器之外,还有一类重要的服务器,称为本地DNS服务器。 这种服务器不在层级之中,而是起到缓存的作用。 常见的WiFi路由器实际上就是一台本地DNS服务器。

为了执行一个DNS查询,在不考虑各种服务器的缓存的情况下,相当于自顶向下地遍历DNS层级。 比如为了查询www.mod.gov.cn的IP地址,我们首先向本地DNS服务器发出查询。 此时本地DNS没有缓存,因此我们必须查询根服务器,找到.cn的顶级域服务器IP。 然后,我们必须在顶级域服务器中找到.gov.cn的次级服务器IP。 此后,我们必须找到负责mod.gov.cn的权威服务器,从那里得到www.mod.gov.cn的IP地址。

DNS查询分为递归查询迭代查询两种。 对DNS服务器而言,在接到查询请求后,如果发现自己不是权威服务器,那么它有两种选择:

  1. 返回一个特殊的报文,指导查询者自己前往下一层域名服务器,这叫做迭代查询
  2. 自己亲自向下一层域名服务器发起查询,这叫做递归查询

通常来说,向本地服务器的查询是递归的,而其他查询是迭代的,这意味着大部分DNS请求实际上是由本地服务器发出的。

为了降低查询流量,DNS服务器通常使用缓存。 DNS缓存和此前的HTTP代理略有不同,其不止缓存最终结果,也会缓存中间的各种域名。 这样,DNS缓存中可以保存顶级域名服务器的地址,从而绕过根服务器。

DNS记录和报文

DNS数据库中实际上保存了以下四元组:

(名字, 值, 类型, 存活时间)

存活时间即该记录还能存在的时间,通常只用于缓存的条目。

类型表明了名字和值之间到底有什么关系,常见的类型有几种:

  1. AAAAA:名字表示主机名,值表示IPv4(或IPv6)地址,表示从主机名到IP地址的映射。
  2. NS:表示该主机名由另外的权威DNS服务器进行解析,值中指明了权威服务器的域名(不是IP地址,这意味着还需要一次DNS解析,但通常不需要,见下)。
  3. CNAME:表示名字是值的一个别名,此时值为规范主机名(Canonical NAME)。
  4. MX:和上一条相同,但是只用于邮件的域名。

DNS报文包括以下内容:

  1. 12字节的头部,包括标识符、标志位和各种四种条目的数目;
  2. 问题:查询的内容;
  3. 回答:包括问题的回答(非权威),其中包括上述资源记录(Resource Record,RR);
  4. 权威回答:包括问题的权威回答;
  5. 附加信息:包括其他信息。

如果发现NS记录,那么可能会把对应权威服务器的IP地址附在附加信息节以减少查询数量。

为了申请新域名,必须在对应的最低级服务器上创建新的条目,然后等待信息传播到顶层服务器去。 如果不止要注册一个域名,而且希望注册一个新的权威服务器以占据一个域名区域,那么我们需要两条记录: 一条NS记录把整个域名指向权威服务器、一条A记录把权威服务器域名指向IP地址。

我们使用Linux下的dig工具模拟域名查询。

www.mod.gov.cn为例,首先输入dig www.mod.gov.cn @a.root-servers.net。 所有根服务器的域名都是*.root-servers.net的格式,这些服务器的IP地址被提前写入所有域名解析器内了,其信息可在这里找到。 其输出为:

# ......
;; QUESTION SECTION:
;www.mod.gov.cn.                        IN      A

;; AUTHORITY SECTION:
cn.                     172800  IN      NS      a.dns.cn.
cn.                     172800  IN      NS      b.dns.cn.
cn.                     172800  IN      NS      c.dns.cn.
cn.                     172800  IN      NS      d.dns.cn.
cn.                     172800  IN      NS      e.dns.cn.
cn.                     172800  IN      NS      f.dns.cn.
cn.                     172800  IN      NS      g.dns.cn.
cn.                     172800  IN      NS      ns.cernet.net.

;; ADDITIONAL SECTION:
a.dns.cn.               172800  IN      A       203.119.25.1
# ......

可以看到所有记录的名字字段都只有最右面的部分(cn..表示从根服务器出发,通常会省略掉),因此可以匹配所有cn顶级域名2。 所有记录都是NS类型,表示该域名的权威服务器为a.dns.cn等。 对应权威服务器的IP地址也出现在附加段中了。

现在继续,执行dig www.mod.gov.cn @a.dns.cn,返回:

# ......
;; QUESTION SECTION:
;www.mod.gov.cn.                        IN      A

;; AUTHORITY SECTION:
mod.gov.cn.             86400   IN      NS      dns2.jfjb.com.cn.
mod.gov.cn.             86400   IN      NS      ns3.cdns.cn.
mod.gov.cn.             86400   IN      NS      dns1.jfjb.com.cn.
mod.gov.cn.             86400   IN      NS      ns2.cdns.cn.
mod.gov.cn.             86400   IN      NS      ns1.cdns.cn.
# ......

可以注意到这里我们直接跳过了gov.cn.这个顶级域名。 实际上,如果我们执行dig gov.cn @a.dns.cn,会得到一个SOA(Start Of Authority record)记录,这说明该服务器也是gov.cn的权威服务器。 所以gov.cncn共享一个权威服务器。 这次的回复附加段中没有DNS服务器的IP地址。

最后执行dig www.mod.gov.cn @ns1.cdns.cn,返回:

# ......
;; QUESTION SECTION:
;www.mod.gov.cn.                        IN      A

;; ANSWER SECTION:
www.mod.gov.cn.         600     IN      CNAME   www.mod.gov.cn.bsgslb.cn.
# ......

现在返回了一个CNAME记录,我们必须从根服务器开始重新进行解析。 幸而我们已经知道cn的权威服务器(缓存!),所以可以直接从那里开始查询。

点对点下载(BitTorrent)

BitTorrent是用于P2P文件分发的流行协议。 参与特定文件分发的所有客户的集合称为集群(Swarm),其中包含只进行上传的种子(Seed)和同时进行上传和下载的对端(Peer)。 描述一个被分发的文件的信息(也称元数据,Metadata)的文件称为洪流文件(Torrent,也叫种子文件)。

为了描述方便,接下来不再区分种子和对端,而把它们统称为对端。

在使用BitTorrent进行下载时,一类特别的服务器,称为追踪器(Tracker),负责保存所有对端的信息。 当一个对端加入下载(或上传)时,其向追踪器注册自己,并周期性地通知它自己仍在集群之中。 新的对端加入时,追踪器向其发送自己保存的对端的一个子集,然后下载方就会尝试与这些对端进行TCP连接,成功建立连接的对端称为“邻近对端”。

BitTorrent以文件的一个固定大小的部分,即块(Chunk),作为交换的单位。 在任何给定的时间,每个对端都该文件的分块的一个子集(相对地,种子持有所有块,即整个文件),而下载者通过TCP连接向所有临近对端查询其用于的块的集合,然后按照“最稀缺最优先”的策略决定请求哪个自己还没有的分块。

当对端收到下载的请求时,其按照“以牙还牙”(Tit-for-tat)的策略决定向哪个邻近对端发送数据。 具体而言,其把所有邻近对端划分为两个集合:阻塞(Choked)和疏通(Unchoked)集合。 上传对端持续测量每个邻近对端的向其上传的比特速率,并选择速度最快的四个加入疏通集合中,这四个对端每10秒更新一次。 除此之外,还从剩余的邻近对端中随机选择一个加入疏通集合中,每30秒轮换一次。 这样,同一时间内最多只有5个对端在疏通集合中。 只有在疏通集合中的对端才会收到上传对端的数据。

通过加入随机选择的对端,这个上传对端有可能变成另一个对端的前四名上传者,因此这个随机选择的对端也可能开始向上传端发送数据,从而加入上传端的前四名上传者中,然后顶替掉速度较低者。 这种随机对换允许对端寻找到最适合自己的对端。

视频与CDN

DASH

我们很容易想到一个利用HTTP进行视频分发的方法,只需要使用GET请求即可。 客户接收服务器数据并收集到缓存中,在自己已经接收到足够多的数据后就开始播放。 流式视频程序周期性地从缓存中抓取图像帧,然后解压缩并播放。

这种方法虽然得到广泛应用,但是仍有一些缺点,即其无法针对不同的客户带宽做出响应。 为此研发出了经HTTP的动态适应性流(Dynamic Adaptive Streaming over HTTP,DASH)。 简单的说,服务器保存同一视频的不同比特率版本,然后客户根据自己的带宽不同选择不同的版本。

为此,服务器需要保存多个视频版本和一个告示文件(Manifest file),其中声明了不同版本的URL和比特率。 客户首先请求这个告示文件,然后得知所有版本,之后选择一个版本发出HTTP GET请求,指出需要的URL和字节范围。 之后客户通过测量接收带宽并使用特定的算法决定使用下一次请求哪一个版本。

内容分发网

为了降低服务器的带宽需求,几乎所有视频流公司都使用内容分发网络(Content Distribution Network,CDN)。 这种CDN可能是公司专有的专用CDN,也可能是第三方CDN

CDN的服务器通常使用两种原则安置:

  1. 深入:向ISP网络中提供大量服务器以深入接入网之中。尽量靠近用户,较难维护。
  2. 邀请做客:把服务器放置在少量IXP(交换中心)中,而非ISP中。维护成本较低,性能相对较差。

CDN通常采用拉取策略,即请求尚未缓存的资源时从其他地方进行拉取,然后保存一份本地副本。

CDN通常是通过DNS实现的,通过向DNS服务器中引入CNAME甚至NS记录,可将指定域名的访问重定向至CDN服务器。 具体而言,当用户通过本地DNS(LDNS)向某域名的权威服务器发起查询时,其中的记录会返回一个CDN服务器的域名,通过查询并访问这个域名即可使用CDN内缓存的资源。

这种实现的优点在于,用户的LDNS的IP地址对CDN的权威域名服务器是已知的,因为其需要查询CDN服务器的域名。 这样,CDN的权威服务器可以根据用户的LDNS(我们知道LDNS通常离用户很近,无论是物理意义上的还是网络意义上的)的来估计用户,从而使用集群选择策略选择最优的CDN服务器。

最简单的策略是选择离用户地理位置最近的CDN服务器集群。 然而地理位置靠近并不代表网络路径长度近或跳数短,也不意味着吞吐量大。 除此之外,还可以选择实时测量策略,即CDN让其每个集群实时地测量到LDNS的网络状态,从而选择最优的集群。 然而LDNS出于安全和性能考虑通常不会响应这种探测请求。

  1. 其他运输层协议可参见维基百科页面 

  2. 这个匹配规则曾导致防火长城对torproject.org的DNS污染误命中mentorproject.org。 

更新时间: