02:应用层

本文最后更新于:1 年前

写在前面

纸上得来终觉浅,绝知此事要躬行。

一、应用层协议原理

研发网络应用程序的核心是写出能够运行在不同的端系统和通过网络彼此通信的程序。因此研发新应用时需要编写将在多台端系统上运行的软件。

1.1 网络应用程序体系结构

应用程序体系结构(application architecture)明显不同于网络体系结构。网络体系结构是固定的,而应用程序体系结构由应用程序研发者设计。
应用程序体系结构目前有两种主流体系结构:客户-服务器体系结构对等(P2P)体系结构

1.1.1 客户-服务器体系结构

在客户-服务器体系结构中,有一个总是打开的主机称为服务器,它服务于来自许多其他称为客户的主机的请求。客户相互之间不直接通信。另一方面,该服务器具有固定的、周知的地址,该地址称为IP地址

客户-服务器体系结构

在一个客户-服务器应用中,常常会出现一台单独的服务器主机跟不上它所有客户请求的情况。为此,配备大量主机的数据中心常被用于创建强大的虚拟服务器。如谷歌在全球拥有30~50个数据中心。一个数据中心能够有数十万台服务器,它们必须要供电和维护。

1.1.2 P2P体系结构

在一个P2P体系结构中,对位于数据中心的专用服务器有最小的(或者没有)依赖。应用程序在间断连接的主机对之间使用直接通信,这些主机对被称为对等方。因为这些对等方通信不必通过专门的服务器,该体系结构被称为对等方到对等方的。
P2P体系结构

P2P最引人入胜的特性之一时自扩展性(self-scalability)。例如,在一个P2P共享文件中,尽管每个对等方都由于请求文件产生工作量,但每个对等方通过向其他对等方分发文件也为系统增加服务能力。P2P体系结构也是成本有效的,因为它们通常不需要庞大的服务器基础设施和服务器带宽。

未来P2P应用面临三个主要挑战:
1 ISP友好。
2 安全性。
3 激励。

需要提及的是,某些应用具有混合的体系结构,它结合了客户-服务器和P2P的元素。例如,对于许多即时通信应用而言,服务器被用于跟踪用户的IP地址,但用户到用户的报文在用户主机之间(无需通过中间服务器)直接发送。

1.2 进程通信

在构建网络应用程序前,还需要对运行在多个端系统上的程序是如何互相通信有所了解。进行通信的实际上是进程(process)而不是程序。一个进程可以被认为是运行在端系统中的一个程序。

当进程运行在相同的端系统上时,它们使用进程间通信机制相互通信。进程间通信的规则由端系统上的操作系统确定。

在两个不同端系统上的进程,通过跨越计算机网络交换报文(message)而相互通信。发送进程生成并向网络中发送报文;接收进程接收这些报文并可能通过将报文发送回去进行响应。

1.2.1 客户和服务器进程

网络应用程序由成对的进程组成,这些进程通过网络相互发送报文。对每对通信进程,我i们通常将这两个进程之一标识为客户(client),而另一个进程标识为服务器(server)。

在给定的一对进程之间的通信会话场景中,发起通信(即在该会话开始时发起与其他进程的联系)的进程被标识为客户,在绘画开始时等待联系的进程是服务器

1.2.2 进程与计算机网络之间的接口

从一个进程向另一个进程发送的报文必须通过下面的网络。进程通过一个称为套接字(socket)的软件接口向网络发送报文和从网络接收报文。

类比说明,进程类比为房子,套接字类比为门。一个进程向另一个房子发送报文就要将报文从门送出去,到另一个房子时再从门进去。

套接字是同一台主机内应用层与运输层之间的接口。由于该套接字是建立网络应用程序的可编程接口,因此套接字也称为应用程序和网络之间的应用程序编程接口(API)。应用程序开发者可以控制套接字在应用端的一切,但是对套接字在运输层端几乎没有控制权(仅限于①选择运输层协议;②也许能设定几个参数,如最大缓存和最大报文长度等)。
应用程序、套接字和下面的运输层协议

1.2.3 进程寻址

在一台主机上运行的进程为了向在另一台主机上运行的进程发送分组,接收进程需要有一个地址。为了标识该接收进程,需要定义两种信息:
——主机的地址;
——定义在目的主机中的接收进程的标识符。

在因特网中,主机由其IP地址标识。除此之外,发送进程还必须指定运行在接收主机上的接收进程(接收套接字)。目的地端口号(port number)用于这里,已经给流行的应用分配了特定的端口号。

1.3 可供应用程序使用的运输服务

在发送端的应用程序将报文推进给该套接字,在该套接字的另一侧,运输层协议负责使该报文进入接收进程的套接字。

包括因特网在内的很多网络提供了不止一种运输层协议。当开发一个应用时,必须要选择一种最能为你的应用需求提供恰当服务的协议。一个运输层协议能够为应用程序提供的服务可大体由四个方面进行分类:可靠数据传输吞吐量定时安全性

1.3.1 可靠数据传输

如果一个协议提供了确保数据交付的服务,就认为提供了可靠数据传输(reliable data transfer)。当一个运输协议提供这种服务时,发送进程只要将其数据传递进套接字,就可以完全相信该数据能无差错地到达接收进程。

当一个运输层协议不提供可靠数据传输时,由发送进程发送地某些数据可能不能够到达接收进程。这可能被容忍丢失的应用(loss-tolerant application)所接受,如一些多媒体应用。

1.3.2 吞吐量

在沿着一条网络路径上的两个进程之间的通信会话场景中,可用吞吐量就是发送进程能够向接收进程交付比特的速率。因为其他会话将共享沿着该网络路径的带宽,并且因为这些会话将会到达和离开,该可用吞吐量将随时间波动。由此衍生出一种服务,即运输层协议能够以某种特定的速率提供确保的可用吞吐量。使用这种服务,应用程序能够请求r比特/秒的确保吞吐量,并且该运输协议能够确保可用吞吐量总是为至少r比特/秒。

具有吞吐量要求的应用程序被称为带宽敏感的应用(bandwidth-sensitive application),例如许多多媒体应用。弹性应用(elastic application)能够根据情况或多或少地利用可供使用的吞吐量,例如电子邮件、文件传输等。

1.3.3 定时

运输层协议也能够提供定时保证。如同具有吞吐量保证那样,定时保证能够以多种形式实现,咯如,发送方注入进套接字中的每个比特到达接收方的套接字不迟于100ms。

这种服务对交互式实时应用程序有很大吸引力。对于非实时的应用,较低的时延总比较高的时延好,但对端到端的时延没有严格的约束。

1.3.4 安全性

运输层协议能够为应用程序提供一种或多种安全性服务。这种服务将在发送和接收进程之间提供机密性,以防该数据以某种方式在这两个进程之间被观察到。
例如,在发送主机中,运输协议能够加密由发送进程传输的所有数据;
接受主机中,运输层协议能够在将数据交付给接收进程之前解密这些数据。

此外,运输协议还能提供除了机密性以外的其他安全性服务,包括数据完整性和端点鉴别。

1.4 因特网提供的运输服务

因特网(更一般的是TCP/IP网络)为应用程序提供两个运输层协议,即UDPTCP。软件开发者为因特网创建新的应用时,首先要选择UDP或者TCP。每个协议为调用它们的应用程序提供了不同的服务集合。

1.4.1 TCP服务

TCP服务模型包括面向连接服务和可靠数据传输服务。

1 面向连接的服务
在应用层数据报文开始流动之前,TCP让客户和服务器互相交换运输层控制信息。这个所谓的握手过程提示客户和服务器,使它们为大量分组的到来做好准备。

在握手阶段后。一个TCP连接(TCP connection)就在两个进程的套接字之间建立了。这条连接是全双工的,即连接双方的进程可以在此连接上同时进行报文收发。

当应用程序结束报文发送时,必须拆除该连接。

2 可靠的数据传送服务
通信进程能够依靠TCP,无差错、按适当顺序交付所有发送的数据。当应用程序的一端将字节流传进套接字时,它能够依靠TCP将相同的字节流交付给接收方的套接字,而没有字节的冗余和丢失

除此之外,TCP协议还具有拥塞控制机制。当发送方和接收方之间的网络出现拥塞时,它会抑制发送进程(客户或服务器)。这种服务不一定能为通信进程带来直接好处,但能为因特网带来整体好处。TCP拥塞控制也试图限制每个TCP连接,使它们达到公平共享网络带宽的目的。

1.4.2 UDP服务

UDP是一种不提供不必要服务的轻量级运输协议,它仅提供最小服务。UDP是无线连接的,因此在两个进程通信前没有握手过程。UDP服务提供一种不可靠数据传送服务,并且没有拥塞控制机制。

1.4.3 因特网运输协议所不提供的服务

TCP提供了可靠的端到端数据传送,在应用层也可以很容易地用SSL来加强以提供安全服务。今天的因特网通常能够为时间敏感应用提供满意的服务,但它不能提供任何定时或带宽保证。

1.5 应用层协议

应用层协议(application-layer protrol)定义了运行在不同端系统上的应用程序进程如何相互传递报文。

特别是应用层协议定义了:
1 交换的报文类型,例如请求报文和响应报文
2 各种报文类型的语法,如报文中的各个字段及这些字段是如何描述的。
3 字段的语义,即这些字段中包含的信息的含义。
4 一个进程何时以及如何发送报文,对报文进行相应的规则

有些应用层协议是由RFC文档定义的,因此它们位于公共域中,例如HTTP。还有很多应用层协议是专用的,有意不为公共域使用。

应用层协议是网络应用的一部分

二、Web和HTTP

在20世纪90年代初期,一个主要的新型应用即万维网(World Wide Web)登上舞台,它极大地改变了人们与工作环境内外交流的方式。对大多数用户而言,Web最具吸引力的是它的按需操作,即用户能看到想看的内容。

2.1 HTTP概况

Web的应用层协议是超文本运输协议(HTTP),它是Web的核心。HTTP由两个程序实现:一个客户和一个服务器程序。客户程序和服务器程序运行在不同的端系统中,通过交换HTTP报文进行会话。HTTP定义了这些报文的结构以及客户和服务器进行报文交换的方式。

Web页面(也叫文档)是由对象组成的。一个对象(object)只是一个文件,诸如一个HTML文件、一个JPEG图形、一个Java小程序或一个视频片段这样的文件,且它们可通过一个URL地址寻址。每个URL地址由两部分组成:存放对象的服务器主机名和对象的路径名。

例如,URL地址http://www.someSchool.edu/someDepartment/picture.gif中www.someSchool.edu就是主机名,/someDepartment/picture.gif就是路径名。

Web浏览器实现了HTTP的客户端,所以被称为浏览器或客户;
Web服务器实现了HTTP的服务器端,它用于存储Web对象,每个对象由URL寻址。

HTTP定义了Web客户向Web服务器请求Web页面的方式,以及服务器向客户传送Web页面的方式。当用户请求一个Web页面时,浏览器向服务器发出对该页面中所包含对象的HTTP请求报文,服务器接收到请求并用包含这些对象的HTTP响应报文进行响应。
HTTP的请求-响应行为

HTTP使用TCP作为它的支撑运输协议。HTTP客户首先发起一个与服务器的TCP连接。一旦连接建立,该浏览器和服务器进程就可以通过套接字接口访问TCP。一旦客户向它的套接字接口发送了一个请求报文,该报文就脱离了客户控制并进入TCP的控制。

HTTP是一个无状态协议(stateless protrol),即不保存关于客户的任何信息。Web是一个客户-服务器体系结构

2.2 非持续连接和持续连接

在许多因特网应用程序中,客户发出一系列请求并且服务器对每个请求进行响应。非持续连接是指每个请求/响应经一个单独的TCP发送,持续连接指所有的请求/响应经相同的TCP发送。

HTTP举例研究持续连接和非持续连接的优缺点

2.2.1 采用非持续连接的HTTP

非持续连接的情况下,从服务器向客户传送一个Web页面的步骤,假设该页面含有一个HTML基本页面和10个JPEG图形,并且这11个对象位于同一台服务器上。该HTML文件的URL为:

http://www.someSchool.edu/someDepartment/home.index

  1. HTTP客户进程在端口号80发起一个到服务器www.someSchool.edu的TCP连接,该端口号是HTTP的默认端口。
  2. HTTP客户经它的套接字向该服务器发送一个HTTP请求报文。请求报文中包含了路径名/someDepartment/home.index
  3. HTTP服务器进程经它的套接字向该服务器发送一个HTTP请求报文。从其存储器(RAM或磁盘)中检索出对象www.someSchool.edu/someDepartment/home.index,在一个HTTP响应报文中封装对象,并通过其套接字向客户发送响应报文。
  4. HTTP服务器进程通知TCP断开该TCP连接。
  5. HTTP客户接收响应报文,TCP连接关闭。该报文指出封装的对象是一个HTML文件,客户从响应报文中提取出该文件,检查该HTML文件,得到对10个JPEG图形的引用
  6. 对每个引用的JPEG图形对象重复前4个步骤。

其中每个TCP连接在服务器发送一个对象后关闭,即该连接并不为其他的对象而持续下来。每个TCP连接只传输一个请求报文和一个响应报文,因此在本例中要产生11个TCP连接。

其中这10个JPEG图形对象是使用10个串行的TCP连接,还是某些JPEG对象使用了一些并行的TCP连接,这可以由用户通过配置浏览器进行控制。

往返时间(RTT)是指一个短分组从客户到服务器然后再返回客户所花费的时间。RTT包括分组传播时延、分组在中间路由器和交换机上的排队时延以及分组处理时延。

当浏览器和Web服务器之间发起一个TCP连接时,会涉及一次”三次握手“过程:

  1. 客户向服务器发送一个小TCP报文段
  2. 服务器用一个小TCP报文段做出确认和响应
  3. 客户向服务器返回确认

三次握手中前两个部分占用了一个RTT。完成前两个部分后,客户结合三次握手的第三部分向该TCP连接发送一个HTTP请求报文,一旦该请求报文到达服务器,服务器就在该TCP连接上发送HTML文件。该HTTP请求/响应占用了一个RTT。因此,总的响应时间就是两个RTT加上服务器传输HTML文件的时间
三次握手过程

2.2.2 采用持续连接的HTTP

非持续连接有两个缺点:

  1. 必须为每一个请求的对象建立和维护一个全新的TCP连接。对于每个连接,客户和服务器都要分配TCP的缓冲区和保持TCP变量。

  2. 每一个对象要经受两倍RTT的交付时延。

    在采用持续连接时,服务器在发送响应后保持该TCP连接打开。在相同的客户与服务器之间的后续请求和响应报文能够通过相同的连接进行传送。一般来说,如果一条连接经过一定时间间隔(一个可配置的超时间隔)仍未被使用,HTTP服务器就关闭该连接。

2.3 HTTP报文格式

HTTP规范包含了对HTTP报文格式的定义。HTTP报文有两种:请求报文和响应报文。

2.3.1 HTTP请求报文

下面提供一个典型的HTTP请求报文:
GET /somedir/page.html HTTP/1.1
Host: www.someschool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr

HTTP请求报文的第一行叫做请求行(request line),其后继的行叫做首部行(header line)。

1 请求行
有3个字段:方法字段URL字段HTTP版本字段。方法字段可以取几种不同的值,包括GET、POST、HEAD、PUT和DELETE,绝大部分采用GET方法。

2 首部行
Host: www.someschool.edu,指明了对象所在的主机。
Connection: close,浏览器告诉服务器不使用持续连接。
User-agent,用来指明用户代理,即向服务器发送请求的浏览器的类型。
Accept-language,表示用户想得到该对象的法语版本(如果服务器中有),否则发送默认版本。

在首部行后有一个“实体体”(entire body)。使用GET方法时实体体为空,在使用POST方法时使用。例如当用户在搜索引擎搜索关键词时,实体体包含的就是用户在表单字段的输入值。

一个HTTP请求报文的通用格式

用表单生成的请求报文不是必须使用POST方法,HTML表单经常使用GET方法,并在所请求的URL中包括输入的数据。例如www.somesite.com/animalsearch?monkeys&bananas。

HEAD方法类似于GET方法,当服务器收到使用HEAD方法的请求时,将会用一个HTTP报文进行响应,但不返回对象。应用程序开发者经常使用HEAD方法进行调试跟踪。

PUT方法常与Web发行工具联合使用,它允许用户上传对象到指定的Web服务器上指定的路径(目录)。同时,它也被那些需要向Web服务器上传对象的应用程序使用。

DELETE方法允许用户或者应用程序删除Web服务器上的对象。

2.3.2 HTTP响应报文

下面提供一条典型的HTTP响应报文,它是对上面请求报文的响应
HTTP:/1.1 200 OK
Connection: close
Data: Tue, 09 Aug 2011 15:44:04 GMT
Server: Apache/2.2.3 (CentOS)
Last-Modified: Tue, 09 Aug 2011 15:11:03 GMT
Content-Length: 6821
Content-Type: text/html
(空行)
(data data data data…)

1 状态行(第1行)
状态行有3个字段:协议版本字段状态码相应状态信息。这里指示服务器正在使用HTTP/1.1,并且一切正常。

2 首部行(2~7行)
Connection: close 告诉客户发送完报文后将关闭该TCP连接;
Date 指示服务器产生并发送该响应报文的日期和时间;
Server 指示该报文是由一台Apache Web服务器产生的,类似于请求报文中的User-agent;
Last-Modified 指示了对象创建或者最后修改的日期和时间,它对对象缓存(既可能在本地客户也可能在网络缓存服务器上)非常重要;
Content-Length 指示了被发送对象中的字节数;
Content-Type 指示了实体体中的对象是HTML文本。

3 实体体:报文的主要部分(data data data…)。

一个HTTP响应报文的通用格式

2.4 用户与服务器的交互:cookie

cookie在[RFC 6265]中定义,它允许站点对用户进行跟踪。

cookie技术有4个组件:

  1. 在HTTP响应报文中的一个cookie首部行;
  2. 在HTTP请求报文中的一个cookie首部行;
  3. 在用户端系统中保留有一个cookie文件,由用户的浏览器进行管理;
  4. 位于Web站点的一个后端数据库。

cookie跟踪用户状态

cookie可以用于标识一个用户。用户首次访问一个站点时,可能需要提供一个用户标识。在后继会话中,浏览器向服务器传递一个cookie首部,从而向该服务器标识了用户。因此cookie可以在无状态的HTTP之上建立一个用户会话层

2.5 Web缓存

Web缓存器(Web cache)也叫代理服务器(proxy server),它是能够代表初始Web服务器来满足HTTP请求的网络实体。Web缓存器有自己的磁盘存储空间,并在存储空间中保存最近请求过的对象的副本

假设浏览器正在请求一个对象,将会发生如下情况:

  1. 浏览器建立一个到Web缓存器的TCP连接,并向Web缓存器中的对象发送一个HTTP请求。
  2. Web缓存器进行检查,看看本地是否存储了该对象副本。如果有,Web缓存器就向客户浏览器用HTTP响应报文返回该对象。
  3. 如果Web缓存器中没有该对象,它就打开一个与该对象的初始服务器的TCP连接。Web缓存器则在这个缓存器到服务器的TCP连接上发送一个对该对象的HTTP请求。在收到该请求后,初始服务器向该Web缓存器发送具有该对象的HTTP响应。
  4. 当Web缓存器接收到该对象时,它在本地存储空间存储一份副本,并向客户的浏览器用HTTP响应报文发送该副本(通过已有的TCP连接)。

所以Web缓存器是服务器同时又是客户。它通常由ISP购买并安装。

部署Web缓存器的原因

  • 它可以大大减少对客户请求的响应时间。
  • 它能够大大减少一个机构的接入链路到因特网的通信量。
  • 它从整体上大大减低因特网上的Web流量,从而改善了所有应用的性能。

通过使用内容分发网络(CDN),Web缓存器正在因特网中发挥着越来越重要的作用。CDN公司在因特网上安装了许多地理上分散的缓存器,因而使大量流量实现了本地化。

2.6 条件GET方法

为了解决存放在缓存器中的对象副本可能已经陈旧的问题,HTTP协议有一种机制,允许缓存器证实它的对象是最新的。它就是条件GET方法

如果

  • 请求报文使用GET方法
  • 请求报文中包含一个"if-Modified-Since:"首部行

那么,这个HTTP请求报文就是一个条件GET请求报文。

三、文件传输协议:FTP

3.1 FTP传输的过程

在一个典型的FTP会话中,用户坐在一台主机前面,向一台远程主机传输文件。为使用户能访问它的远程账户,用户必须提供一个用户标识和口令。用户通过一个FTP用户代理FTP交互。

具体步骤如下:

  1. 用户首先提供远程主机的主机名,使本地主机的FTP客户进程建立一个到远程主机FTP服务器进程的TCP连接
  2. 用户接着提供用户标识和口令,作为FTP命令的一部分在该TCP连接上传送。
  3. 一旦该服务器向该用户授权,用户可以将存放在本地文件系统中的一个或多个文件复制到远程文件系统(反之亦然)。

3.2 HTTP和FTP的对比

3.2.1 共同点

  • 都是文件传输协议
  • 都运行在TCP上

3.2.2 不同点

  • FTP使用了两个并行的TCP连接来传输文件,一个是控制连接(control connection),一个是数据连接(data connection)。控制连接用于在主机之间传输控制信息,如用户标识、口令、文件命令等。数据连接用于实际发送一个文件。我们称FTP是带外连接(独立的控制连接)的。HTTP是在传输文件的同一个TCP连接中发送请求和响应首部行的。因此,HTTP是带内连接的。
  • FTP服务器必须在整个会话期间保留用户的状态(state)。服务器必须把特定的用户账户与控制连接联系起来,大大限制了FTP同时维持的会话总数。HTTP是无状态的,它不必对任何用户状态进行跟踪。

对FTP而言,控制连接贯穿了整个用户会话期间,但是对会话中的每一次文件传输都需要建立一个新的数据连接(即数据连接是非持续的)。

3.3 FTP命令和回答

详见 RFC959

四、因特网中的电子邮件

4.1 因特网电子邮件系统和它的关键组件

因特网电子邮件系统有3个主要组成部分:用户代理(user agent)、邮件服务器(mail server)和简单邮件传输协议(SMTP)。

1 用户代理允许用户阅读、回复、转发、保存和撰写报文。当发送方完成邮件撰写时,邮件代理向其邮件服务器发送邮件,此时邮件放在邮件服务器的外出报文队列中。

2 邮件服务器形成了电子邮件体系结构的核心。每个接收方在其中的某个邮件服务器上有一个邮箱(mailbox),邮箱管理和维护着发送给用户的报文。当用户要在他的邮箱中读取该报文时,包含他邮箱的邮件服务器要鉴别用户。

如果发送方的服务器不能将邮件交付给接收方的服务器,发送方的邮件服务器在一个报文队列(message queue)中保持该报文并在以后尝试再次发送。通常每30分钟进行一次尝试,如果几天后仍不能成功,服务器就删除该报文并以电子邮件的形式通知发送方。

3 SMTP是因特网电子邮件中主要的应用层协议。它使用TCP可靠数据传输服务,从发送方的邮件服务器向接收方的邮件服务器发送邮件。SMTF也有两个部分:运行在发送方邮件服务器的客户端和接收方邮件服务器的服务器端

4.2 SMTP

SMTP是因特网电子邮件应用的核心,用于从发送方的邮件服务器发送报文到接收方的邮件服务器。

假设Alice想给Bob发送一封简单的ASCII报文:

  1. Alice调用她的邮件代理程序并提供Bob的邮件地址,撰写报文,然后指示用户代理发送该报文。
  2. Alice的用户代理把报文发给他的邮件服务器,在那里该报文被放在报文队列中。
  3. 运行在Alice的邮件服务器上的SMTP客户端发现了报文队列中的这个报文,它就创建一个到运行在Bob的邮件服务器上的SMTP服务器TCP连接
  4. 在经过一些初始SMTF握手后,SMTP客户通过该TCP连接发送Alice的报文。
  5. 在Bob的邮件服务器上,SMTP的服务器端接收该报文。Bob的邮件服务器将该报文放入Bob的邮箱中。
  6. 在Bob方便的时候,他调用用户代理阅读该报文。

SMTP一般不使用中间服务器发送邮件。而且它用的是持续连接,通过同一个TCP连接发送所有报文。

4.3 HTTP和SMTP的对比

4.3.1 共同点

  • 都用于从一台主机向另一台主机传送文件。
  • 进行文件发送时,二者都使用持续连接

4.3.2 不同点

一、

  • HTTP主要是一个拉协议(pull protocol),即在方便的时候,用户使用HTTP从服务器拉取这些信息。TCP由想接收文件的机器发起的。
  • SMTP基本是一个推协议(push protocol),即发送邮件服务器把文件推向接收邮件服务器。TCP由要发送该文件的机器发起。

二、

  • SMTP要求每个报文使用7比特ASCII码格式。如果文件包含非7比特ASCII字符,则必须要按照7比特ASCII码进行编码。
  • HTTP没有格式限制。

三、

  • 在处理一个既包含文本又包含图形(或其他)的文档时,HTTP把每个对象封装到响应报文中。
  • SMTP把所有报文对象放在一个报文之中。

4.4 邮件报文格式和MIME

当发送电子邮件时,一个包含环境信息的首部位于报文体前面。这些环境信息包括在一系列首部行中,这些行由RFC 5322定义。注意这里的首部行不同于SMTP命令,SMTP命令是握手协议的一部分。

一个典型的报文首部如下:
From: alice@crepes.fr
To: bob@hamburger.edu
Subject: Searching for the meaning of life

4.5 邮件访问协议

目前用户是通过在用户端系统上运行的客户程序来阅读电子邮件。用户通常在本地PC上运行一个用户代理程序,它访问存储在总是保持开机的共享邮件服务器(由用户的ISP维护)上的邮箱。

为了接收方能够通过用户代理获得某ISP上的邮件服务器上的邮件,目前有一些流行的邮件访问协议,包括第三版的邮局协议(POP3)、因特网邮件访问协议(IMAP)和HTTP

电子邮件协议及其通信实体

4.5.1 POP3

POP3是一个极为简单、功能相当有限的邮件访问协议,由RFC1939定义。随着建立TCP连接,POP3按照三个阶段进行工作:

  1. 特许(authorization)
    用户代理发送(以明文形式)用户名和口令以鉴别用户。
  2. 事务处理
    用户代理取回报文,还能对报文做删除标记,取消报文删除标记,以及获取邮件的统计信息。
  3. 更新
    出现在客户发出quit命令之后,结束该POP3会话。同时,该邮件服务器删除哪些被标记为删除的报文。

4.5.2 IMAP

4.5.3基于Web的电子邮件

五、DNS:因特网的目录服务

因特网上的主机可以使用多种方式进行标识,其中的一种标识方法是主机名(hostname)。然而,主机名几乎没有提供关于主机在因特网中位置的信息,而且以不定长的字母数字组成,路由器难以处理。由于这些原因,主机也使用IP地址(IP address)进行标识。

一个IP地址由四个字节组成,并有着严格的层次结构,如121.7.106.83,其中的每个字节都被句点分隔开,表示了0~255的十进制数字。当从左至右扫描它时,会得到越来越具体的关于主机位于因特网何处的信息。

5.1 DNS提供的服务

域名系统(DNS)的主要任务是进行主机名到IP地址转换的目录服务

DNS是:
①一个由分层的DNS服务器(DNS server)实现的分布式数据库
②一个使得主机能够查询分布式数据库的应用层协议。

DNS通常是由其他应用层协议所使用的(不直接面向用户),包括HTTP、SMTP和FTP,将用户提供的主机名解析为IP地址。例如,当用户要将一个HTTP请求报文发送到Web服务器时,必须要获得该网页的IP地址:

  • 同一台用户主机上运行着DNS应用的客户端。
  • 浏览器从URL抽取出主机名,并将主机名传给DNS应用的客户端。
  • DNS客户向DNS服务器发送一个包含主机名的请求。
  • DNS客户最终会收到一份回答报文,其中含有对应于该主机名的IP地址。
  • 一旦浏览器接收到该IP地址,它能够向位于该IP地址80端口的HTTP服务器进程发起一个TCP连接。

DNS将会为因特网应用带来大量时延。目前想获得的IP地址通常就缓存在“附近的”DNS服务器中,这有助于减少DNS的网络流量和平均时延。

除了上述的主机名到IP地址的转换,DNS还提供了一些重要的服务:

  • 主机别名
  • 邮件服务器别名
  • 负债分配
  • ……

DNS由RFC定义,它是一个复杂的系统,这里不再详述。

5.2 DNS工作机理概述

从用户之际上调用应用程序的角度看,DNS是一个提供简单、直接的转换服务的黑盒子,事实上它的构造非常复杂。DNS由分布于全球的大量DNS服务器以及定义了DNS服务器与查询主机通信方式的应用层协议组成

采用单一DNS服务器(集中式设计)会有如下问题:

  • 单点故障(a single point of failure)
  • 通信容量(traffic volume)
  • 远距离的集中式数据库(distant centralized database)
  • 维护(maintenance)

因此,DNS采用了分布式的设计方案。

5.2.1 分布式、层次数据库

DNS使用了大量DNS服务器,它们以层次方式组织,并且分布在全世界范围内。没有一台DNS服务器拥有因特网上所有主机的映射,该映射分布在所有的DNS服务器上

大致说来,有三种类型的DNS服务器:

  • 根DNS服务器
    在因特网上有13个根DNS服务器(标号从A到M),大部分位于北美洲。为了提高安全性和可靠性,每台“服务器”实际上是一个服务器网络
  • 顶级域(TLD)DNS服务器
    这些服务器负责顶级域名,如com、org、net、edu等以及所有国家的顶级域名
  • 权威DNS服务器
    在因特网上具有公共可访问主机(如Web服务器和邮件服务器)的组织(机构)必须提供公共可访问的DNS记录,这些记录将这些主机的名字映射为IP地址。这个组织(机构)能够选择实现自己的权威DNS服务器收藏这些DNS记录,也可以选择将这些记录存储在第三方的权威DNS服务器中。

DNS服务器的部分层次结构

除了在层次结构中的三种DNS服务器,还有一类,叫做本地DNS服务器,它起到一个代理的作用。对于某居民区ISP,本地DNS服务器通常与主机相隔很近。

各种DNS服务器的交互

主机、服务器之间的查询有两种形式:

  • 递归查询。在该模式下DNS 服务器接收到客户机请求,必须使用一个准确的查询结果回复客户机。如果DNS 服务器本地没有存储查询DNS 信息,那么该服务器会询问其他服务器,并将返回的查询结果提交给客户机。客户机和服务器之间的查询是递归查询。
    递归查询告诉客户机IP地址
  • 迭代查询。DNS 服务器会向客户机提供其他能够解析查询请求的DNS 服务器地址,当客户机发送查询请求时,DNS 服务器并不直接回复查询结果,而是告诉客户机另一台DNS 服务器地址,客户机再向这台DNS 服务器提交请求,依次循环直到返回查询的结果为止。
    服务器之间的查询是迭代查询

5.2.2 DNS缓存

为了改善时延性能并减少在因特网上到处传输的DNS报文数量,DNS广泛使用了缓存技术。在一个请求链中,当某DNS服务器接收一个DNS回答时,它能将该回答中的信息缓存在本地存储器中。由于主机和和主机名与IP地址的映射不是永久的,DNS服务器在一段时间后(通常设置为两天)将丢弃缓存的信息。

5.3 DNS记录和报文

共同实现DNS分布式数据库的所有DNS服务器存储了资源记录(RR),RR提供了主机名到IP地址的映射。每个DNS回答报文包含了一条或多条RR。

RR是一个包含了下列字段的4元组:
(Name,Value,Type,TTL)

关于RR的详细内容以后再补。

5.3.1 DNS报文

DNS报文中各字段的语义如下:

DNS报文格式

  • 前12个字节是首部区域
    1 标识符是一个16比特的数。用于标识该查询,它会被复制到回答报文中,以便让客户用它来匹配发送的请求和接收到的回答。
    2 标志字段中含有若干标志
    1比特的“查询/回答”标志位指出报文是查询报文(0)还是回答报文(1);
    当某DNS服务器是所请求名字的权威DNS服务器时,1比特的“权威的”标志位被置入;
    如果客户在该DNS服务器没有某记录时希望它执行递归查询,将设置1比特的“希望递归”标志位;
    如果该DNS服务器支持递归查询,在它的回答报文中会显示1比特的“递归可用”标志位。
    3 除此之外,首部区域还有4个有关数量的字段,它们分别指出了4类数据区域出现的数量。
    • 问题区域包含着正在进行的查询信息。该区域包括:
      1 名字字段,指出正在被查询的主机名字。
      2 类型字段,指出有关该名字的正被询问的问题类型。
    • 回答区域包含了对最初请求的名字的资源记录
    • 权威区域包含了其他权威服务器的记录。
    • 附加区域包含了其他有帮助的记录。

5.3.2 在DNS数据库中插入记录

如果你想注册域名,需要向注册登记机构(register)提供基本和辅助权威DNS服务器的名字和IP地址。对这两个权威DNS服务器,该注册登记机构确保将一个类型NS和一个类型A的记录输入TLD com服务器。

例如,输入如下信息:
(networkutopia.com, dnsl.networkutopia.com, NS)
(dnsl.networkutopia.com, 212.212.212.1, A)

除此之外,你还需要确保用于Web服务器的类型A资源记录和用于邮件服务器的类型MX资源记录被输入到你的权威DNS服务器中。

六、P2P应用

P2P体系结构不同于客户-服务器体系结构,成对间歇地主机(称为对等方)彼此直接通信。有两种特别适合于P2P设计的应用。

  • 文件分发,其中应用程序从单个源向大量的对等方分发一个文件。
  • 分布在大型对等方社区中的数据库。

6.1 P2P文件分发

6.1.1 P2P体系结构的扩展

假设,
us\bm{u_s}表示服务器接入链路的上载速率;
ui\bm{u_i}表示第i个对等方接入链路的上载速率;
di\bm{d_i}表示第i个对等方接入链路的上载速率;
F\bm{F}表示被分发的文件长度(以比特计);
N\bm{N}表示要获得的该文件副本的对等方的数量;
D\bm{D}是所有N个对等方得到该文件的副本所需要的时间。

对于客户-服务器体系结构,

Dmax{NFus,Fdmin}D \ge max \{ \frac {NF}{u_s}, \frac {F}{d_{min}}\}

对于P2P体系结构,

Dmax{Fus,Fdmin,NFus+i=1Nui}D \ge max \{ \frac {F}{u_s}, \frac {F}{d_{min}}, \frac {NF}{u_s+\sum_{i=1}^N u_i}\}

二者分发时间对比如下图,

P2P和客户-服务器体系结构的分发时间

6.1.2 BitTorrent

BitTorrent是一种用于文件分发的流行P2P协议。在BitTorrent中,参与一个特定文件分发的所有对等方的集合被称为一个洪流(torrent)。在一个洪流中的对等方彼此下载等长度的文件块(chunk),一般块长度为256KB。当一个对等方首次加入一个洪流时,它没有块。随着时间流逝,它累积了越来越多的块,当它下载块时,也为其他对等方上载了多个块。任何对等方可能在任何时候仅具有块的子集就离开洪流,并可以重新加入洪流。

每个洪流有一个基础设施结点,称为追踪器(tracker)。当一个对等方加入该洪流中时,它向追踪器注册自己,并周期性地通知追踪器它仍然在该洪流中。以这种方式,追踪器跟踪正参与在洪流中的对等方。

当一个新的对等方A加入该洪流时,追踪器随机地从参与对等方的集合中选择对等方的一个子集,并将这些对等方的IP地址发给A。A会尝试与它们创建并行的TCP连接,所有成功与A创建连接的对等方称为**“邻近对等方**”。随着时间流逝,它们中有些可能离开,而其余的对等方可能加入,因此,一个对等方的邻近对等方将随时间波动。
BitTorrent分发文件

在任何给定的时间,每个对等方将具有来自该文件的块子集,并且不同对等方具有不同的子集。A周期性地询问 每个邻近对等方具有的块列表,之后A可以对它还没有的块发出请求(TCP)。

A将做出两个重要决定:-请求哪些块?-为哪些邻近对等方发送块?

  • 在决定请求哪些块的过程中,A会使用一种称为最稀缺优先的技术。思路是,针对它没有的块在它的邻居中决定最稀缺的块,并首先请求最稀缺的块。这样,最稀缺的块得到更为迅速地分发,其目标是均衡每个块在洪流中地副本数量。
  • 为了决定响应哪个请求,A根据当前能够以最高速率向它提供数据的邻居给出优先权。

6.2 分布式散列表

在P2P系统中,每个P2P对等方将保持(键,值)对仅占总体的一个小子集,并且允许任何一个对等方用一个特别的键来查询该分布式数据库。分布式数据库则将定位拥有该相应(键,值)对的对等方,然后向查询的对等方返回该(键,值)对。任何对等方也将允许在数据库中插入新键-值对。这样一种分布式数据库被称为分布式散列表(DHT)。

详细内容以后需要再补

七、TCP套接字编程

7.1 UDP套接字编程

UDP 客户 / 服务器程序使用的套接字函数

以下代码演示客户如何使用UDP套接字向服务器发送消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
## UDPClient.py
# socket模块形成了在Python中所有网络通信的基础
from socket import *
# 提供服务器的IP地址或主机名
serverName = 'hostname'
# 置入端口号
serverPort = 12000
# 创建客户的套接字,第一个参数指示了地址簇,第二个参数指示它是一个UDP套接字
clientSocket = socket(AF_INET, SOCK_DGRAM)
# 提示用户输入报文
message = raw_input('Input lowercase sentence:')
# 经一个UDP套接字发送报文
clientSocket.sendto(message,(serverName, serverPort))
# 将服务器传回的报文置入到变量中
modifiedMessage, serverAddress = clientSocket, recvfrom(2048)
# 打印输出报文
print modifiedMessage
# 关闭套接字,关闭进程
clientSocket.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
## UDPServer.py
# socket模块形成了在Python中所有网络通信的基础
from socket import *
# 置入端口号
serverPort = 12000
# 创建服务器的套接字,第一个参数指示了地址簇,第二个参数指示它是一个UDP套接字
serverSocket = socket(AF_INET, SOCK_DGRAM)
# 将端口号与套接字绑定在一起
serverSocket.bind((", serverPort))
print "The server is ready to receive"
# 该循环允许UDPServer无限期地接收并处理来自客户的分组
while true:
# 将分组数据和客户地址置入
message, clientAddress = serverSocket.recvfrom(2048)
# 将数据小写转换为大写
modifiedMessage = message.upper()
# 将所得分组发送给服务器的套接字
serverSocket.sendto(modifiedMessage, clientAddress)

7.2 TCP套接字编程

TCP是一个面向连接的协议。在客户和服务器能够开始互相发送数据之前,它们先要握手和创建一个TCP连接(客户套接字和服务器套接字)。

TCP 客户 / 服务器程序使用的套接字函数

以下代码演示客户如何使用TCP套接字向服务器发送消息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from socket import *
serverName = 'servername'
serverPort = 12000
# 创建客户的套接字,第一个参数指示了地址簇,第二个参数指示它是一个TCP套接字
clientSocket = socket(AF_INET, SOCK_STREAM)
# 执行三次握手,并创建起一条TCP连接
clientSocket.connect((serverName, serverPort))
# 提示用户输入报文
sentence = raw_input('Input lowercase sentence')
# 通过套接字进入TCP连接发送报文
clientSocket.send(sentence)
# 将服务器传回的报文置入到变量中
modifiedSentence = clientSocket.recv(1024)
print 'From Server:', modifiedSentence
clientSocket.close()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## TCPServer.py
from socket import *
serverPort = 12000
# 创建服务器的套接字,第一个参数指示了地址簇,第二个参数指示它是一个UDP套接字
serverSocket = socket(AF_INET, SOCK_DGRAM)
# 将端口号与套接字绑定在一起
serverSocket.bind((", serverPort))
# 等待并聆听某个客户敲门,参数定义了请求连接的最大数(至少为1)
serverSocket.listen(1)
print "The server is ready to receive"
# 该循环允许TCPServer无限期地接收并处理来自客户的分组
while true:
# 创建一个新套接字,由这个特定用户专用
connectionSocket, addr = serverSocket.accept()
# 将分组数据和客户地址置入
sentence = connectionSocket.recv(1024)
# 将数据小写转换为大写
capitalizedSentence = sentence.upper()
# 将所得分组发送给服务器的套接字
connectionSocket.send(capitalizedSentence)
connectionSocket.close()

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!