《计算机网络:自顶向下方法》笔记:02.应用层

本章思维导图

ch2 应用层

一、应用层协议原理

研发网络应用的核心是写出能够运行在不同端系统和能通过网络彼此通信的程序;值得注意的是,我们不需要写在网络核心设备(如路由器或者链路层交换机)上运行的软件,网络核心设备中没有应用层软件,它并不在应用层上起作用,而仅在较低层起作用。网络应用只应在端系统上存在,通过网络基础设施提供的服务,实现应用进程彼此通信。这种设计方式即将应用程序限制在端系统的方法,促进了大量网络应用程序的迅速研发和部署。这也体现了因特网体系结构的复杂性大多位于网络的边缘

1.应用程序体系结构

应用程序体系结构由应用程序研发者设计,规定了如何在端系统上组织应用程序。

1.1 客户-服务器体系结构

客户-服务器(Client/Server)结构中,

(1)服务器:

  • 一直运行,它接收和服务来自许多客户的主机请求。具有固定、周知的地址,称为IP地址
  • 会有性能阈值,可靠性、扩展性比较差

(2)客户:

  • IP可以是动态的
  • 客户只能与服务器通信,客户之间不能通信

(3)经典应用:Web、FTP、Telent、电子邮件等

1.2 P2P体系结构

P2P(Peer to Peer)结构中,

(1)对等方:应用程序在任意端系统之间直接相互通信,这些主机被称为对等方

(2)几乎没有一直运行的服务器,对位于数据中心的专用服务器有着最小(或者没有)依赖。

(3)也可以理解为,每个端系统既是服务器又是客户,扩展性强

(4)主机间歇性连接并且可以改变IP地址,难以管理,安全性和可靠性遭受挑战

(5)经典应用:文件共享软件、对等方协助下载加速器(迅雷)、因特网电话

1.3 混合体系结构

某些应用具有混合的体系结构,它们结合了客户-服务器和P2P这两种体系结果,比如许多的即时通讯工具,服务器用来跟踪用户IP地址提供服务,但是用户之间的通信则使用P2P

2.进程通信

在操作系统中,实际进行通信的是进程而不是应用程序。

一个进程可以被认为是运行在端系统中的一个程序,当多个进程运行在相同的端系统上时,它们使用进程间通信机制相互通信,而进程间通信的规则是由端系统上的操作系统确定的。

当进程运行在不同的端系统(可能是不同的操作系统)上时,它们跨越计算机网络交换报文相互通信;发送进程产生报文并且向网络中发送,接收进程接收报文并对此作出响应(不响应也是一种响应)。

2.1 客户和服务器进程

通常将每对通信进程之一标识为客户,而另一个进程标识为服务器

定义客户进程为发起通信的进程

服务器进程为等待联系的进程

即使在P2P中,也有这二者之分,只不过P2P中,一个进程既可以是客户也可以是服务器,取决于它是发起通信还是等待通信。

2.2 进程寻址

客户进程为了向目的进程发送报文,需要知道接收进程(更为准确的说是,接收进程对应的套接字)的标记。

该标记由三部分组成:

  • 接收进程所在的主机地址:由主机IP地址标识
  • 所采用的传输层协议:TCP/UDP
  • 接收进程在该主机中的标识符:由该主机端口号标识。一些常用应用程序有着固定的端口号,比如Web服务器使用80端口、邮件服务器(运行SMTP协议)使用25端口等

2.3 套接字

一个进程向另一个进程发送报文必须通过下面的网络,进程通过一个称为套接字(socket)的软件接口向网络发送和接收报文。套接字是同一台主机内应用层和运输层之间的接口,由于该套接字是建立网络应用程序的可编程接口,因此套接字也被称为应用程序和网络之间的应用编程接口(Application Programming Interface,API)。

应用程序开发者可以控制套接字在应用层的一切内容,但是对于运输层的相关部分,几乎没有控制权,仅限于:选择传输层协议和设定几个传输层参数,比如最大缓存和最大报文段长度

应用进程、套接字和下面的运输层协议关系见下图:

socket

TCP/UDP具体的socket组成暂时没写,以后再看,中科大MOOC第二章的ppt

3.因特网提供的运输服务

进程通信需要经过套接字到运输层,运输层能够提供的服务有哪些要求?可以从四个方面进行考虑:可靠数据传输、吞吐量、时延、安全性

目前因特网(更一般的是TCP/IP网络)为应用程序提供连个运输层协议,即TCP(Transmission Control Protocol,传输控制协议)和UDP(User Datagram Protocol,用户数据包协议),这里会简单介绍一下它们各自的特点,详细的会在第三章中描述

3.1 TCP

TCP能提供:

  • 面向连接的服务
  • 可靠数据传输服务
  • 还具有拥塞控制机制

不能提供:时延保证、最小吞吐保证、安全

3.2 UDP

UDP服务是一种无连接的运输协议。它提供不可靠数据传输服务,不能提供:可靠、拥塞控制、时延保证、带宽保证

UDP存在的必要性:

  • 无需建立连接,省去了建立连接时间,适合事务性的应用
  • 不做可靠性的工作,适合对实时性要求高而对正确性要求不高的应用。而TCP正因要保证可靠性,付出了时间代价(检错重发)
  • 没有拥塞控制和流量控制,应用能够按照设定的速度发送数据。而TCP有流量控制和拥塞控制,应用发送数据的速度和主机向网络发送的实际速度是不同的

简而言之,相对来说,TCP面向连接,可靠但慢;UDP无连接,不可靠但快

3.3 SSL

有关安全性:TCP/UDP都没有提供加密机制,因此有了TCP的加强版,成为安全套接字层(Secure Sockers Layer, SSL),但SSL并不是第三种传输协议,而是一种对TCP的加强,并且是在应用层上实现的

4.应用层协议

应用层协议定义运行在不同端系统上的应用程序进程如何相互传递信息。涉及的内容包括:

  • 交换的报文类型(是请求还是响应)
  • 各种报文类型的语法
  • 字段的语义
  • 一个进程何时收发报文并如何对报文进行响应的规则

5.本书涉及的网络应用

即将介绍的应用包括:Web、文件传输、电子邮件、目录服务和P2P

需要区分网络应用和应用层协议!!!

应用层协议是网络应用非常重要的一部分,例如Web应用包含:HTTP协议、文档格式标准(HTML)、Web浏览器(客户端)、Web服务器。电子邮件应用包含:SMTP(电子邮件的应用层协议)、邮件服务器、邮件客户程序(例如gmail)、定义电子邮件报文结构的标准

二、Web和HTTP

1. Web和HTTP概况

超文本传输协议(Hyper Text Transfer Protocol,HTTP)是Web的应用层协议,定义了报文结构和报文交换的方式,它是Web的核心。HTTP由两个程序实现,一个客户端程序一个服务器程序。

客户端程序是Web浏览器服务器程序是Web服务器,用于存储Web对象

Web页面是由对象组成的,一个对象只是一个文件(诸如一个HTML文件、一个JPG图形、一个视频),且它们可以通过一个URL地址进行寻址。URL地址由两部分组成:存放对象的服务器主机名对象的路径名

客户和服务器交互的基本思想是:用户请求一个Web页面(如点击一个超链接)时,浏览器向服务器发出对发出对该页面中所包含对象的HTTP请求报文,服务器接收到请求并用包含这些对象的HTTP响应报文进行响应

HTTP使用TCP作为它的支撑运输层协议(而不是UDP),HTTP客户首先发起一个与服务器的TCP连接。一旦连接建立,该浏览器和服务器进程就可以通过套接字接口访问 TCP。一旦客户向它的套接字接口发送了一个请求报文,该报文就脱离了客户控制并进入 TCP的控制,TCP为HTTP提供可靠数据传输服务。这里我们看到了分层体系结构最大的优点,即 HTTP协议不用担心数据丢失,也不关注TCP从网络的数据丢失和乱序故障中恢复的细节,那是TCP以及协议栈较低层协议的工作

服务器向客户发送被请求的文件,而不存储任何关于该客户的状态信息。假如某个特定的客户在短短的几秒内两次请求同一个对象,服务器并不会因为刚刚为该客户提供了该对象就不再做出反应,而是重新发送该对象,就像服务器已经完全忘记不久之前所做过的事一样。所以HTTP是一个无状态协议( stateless protocol)。此外很显然的是,Web使用了客户-服务器应用程序体系结构

当浏览器收到Web页面后,向用户显示该页面。两个不同的浏览器也许会以不同的方式解释(即向用户显示)该页面。HTTP与客户如何解释一个 Web页面毫无关系

2. 非持续连接和持续连接

使用TCP进行运输时,应用程序的研制者需要做一个重要决定,即使用非持续连接还是持续连接

使用非持续连接:每个请求/响应对用一个单独的TCP连接发送。HTTP1.0 默认使用非持续连接

使用持续连接:所有的请求/响应对经相同的TCP连接发送。HTTP1.1 默认使用非持续连接的流水方式

书中以HTTP为例,分析了两种连接方式的具体区别。

2.1 非持续HTTP

(1)在非持续连接情况下,从服务器向客户传送一个Web页面(假设其有1个HTML基本文件和10个JPG图片)的步骤:

  • HTTP客户进程在端口号80发起一个到服务器的TCP连接
  • HTTP客户经它的套接字向该服务器发送一个HTTP请求报文
  • HTTP服务器进程经它的套接字接收该请求报文,从其存储器(RAM或磁盘)中检索出对象,在一个HTTP响应报文中封装对象,并通过其套接字向客户发送响应报文
  • HTTP服务器进程通知TCP 断开该TCP连接。(但是直到TCP 确认客户已经完整地收到响应报文为止,它才会实际中断连接。)
  • HTTP客户接收响应报文,TCP连接关闭。该报文指出封装的对象是一个 HTML文件,客户从响应报文中提取出该文件,检查该HTML文件,得到对10个JPG图形的引用(注意第一次返回会是HTML文件,随后才是其他对象,这也解释了为什么网速慢时图片是后显示的)
  • 对每个引用的JPEG图形对象重复前4个步骤

显然每个TCP 连接在服务器发送一个对象后关闭,即该连接并不为其他的对象而持续下来。值得注意的是每个TCP连接只传输一个请求报文和一个响应报文。因此在本例中,当用户请求该Web页面时,要产生11个TCP连接。(默认使用串行TCP连接,其实也有并行TCP连接,会更快)

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

非持续HTTP总的响应时间就是:两个RTT(一个用于创建TCP连接,一个用于请求和接收文件) +服务器传输HTML文件的时间

(3)非持续连接的缺点

  • 每个对象要两个RTT
  • 操作系统必须为每个TCP连接分配资源

2.2 持续HTTP

持续HTTP就是,服务器在发送响应后保持该TCP连接打开。在相同的客户与服务器之间,后续的请求和响应报文能够通过相同的连接进行传送。不但一个完整的页面可以通过同一个连接传送,同一台服务器上的多个页面也可以通过同一个连接发送。这就提高了效率

持续HTTP又可以分为:

  • 非流水方式:客户端只能在收到前一个响应后才能发出新的请求(前一个回完才能发下一个),每个引用对象花费一个RTT
  • 流水方式:客户端遇到一个引用对象就立即产生一个请求(不用等前一个回完就直接发下一个请求),所有引用(小)对象只花费一个RTT是可能的

如果一条连接经过一定时间间隔(可配置)仍未被使用,HTTP 服务器就关闭该连接

3. HTTP报文格式

3.1 HTTP请求报文

一个请求报文的通用格式见下图:

HTTP request message

一个请求报文具有至少一行的内容。请求行的结构:

  • 第一行称为请求行,包含三个内容:方法字段(GET、POST、HEAD、PUT、DELETE等)、URL字段(请求对象的标志)、HTTP版本

    • 绝大部分的HTTP请求报文使用GET方法。当浏览器请求一个对象时,使用GET方法,在URL字段带有请求对象的标识。
    • 当用户提交表单时,HTTP客户常常使用POST方法,例如当用户向搜索引擎提供搜索关键词时。
    • HEAD方法类似于GET方法。当服务器收到一个使用HEAD方法的请求时,将会用一个HTTP报文进行响应,但是并不返回请求对象。应用程序开发者常用HEAD方法进行调试跟踪。
    • PUT方法常与Web 发行工具联合使用,它允许用户上传对象到指定的Web服务器上指定的路径(目录)。PUT方法也被那些需要向Web服务器上传对象的应用程序使用。
    • DELETE方法允许用户或者应用程序删除Web服务器上的对象。
  • 请求行的各行被称为首部行,包含是否在发送完响应报文后关闭TCP连接的Connection;请求的主机地址(该头部信息被Web高速缓存所要求);浏览器版本;可接受的语言等头部信息

  • 首部行之后有一个空行

  • 空行之后便是请求的实体体。如果请求行使用get实体体为空,使用POST会在实体体传递用户填写的表单内容,或者传递其它一些二进制流数据等。值得注意的是,表单也不一定必须使用POST方法。也经常使用GET方法,不过并不会放在实体体中,而是在url中包含输入的数据

下面是一段典型的HTTP的请求报文,第一行请求行指定GET方法,提供url和HTTP1.1的版本,下面四行都是首部行,第一行指明对象所在的主机(该首部行提供的信息是Web代理高速缓存所要求的,尽管在该主机中已经有一条 TCP连接存在了);首部行第二行是该浏览器告诉服务器不要麻烦地使用持续连接;首部行第三行用来指明用户代理,即向服务器发送请求的浏览器的类型。这里浏览器类型是 Mozilla/5.0,即 Firefox浏览器;首部行第四行表示用户想要得到法语版本

1
2
3
4
5
GET /somedir/page.html HTTP/1.1
Host: www.someschool.edu
Connection: close
User-agent: Mozilla/5.0
Accept-language: fr

3.2 HTTP响应报文

一个响应报文的通用格式见下图:

HTTP ask message

除了第一行为状态行,剩下内容和请求报文相同。状态行第一部分是HTTP的版本,后面为状态码和相关的短语。常用的状态码极其短语有以下几种:

  • 200 OK:请求成功,信息在返回的响应报文中。
  • 301 Moved Permanently:请求的对象已经被永久转移了,新的URL定义在响应报文的Location:首部行中。客户软件将自动获取新的URL。
  • 400 Bad Request:一个通用差错代码,指示该请求不能被服务器理解。
  • 404 Not Found:被请求的文档不在服务器上。很常见有木有
  • 505 HTTP Version Not Supported:服务器不支持请求报文使用的HTTP 协议版本。

下面是一段典型的HTTP的响应报文。有三个部分:1个初始状态行,6个首部行,然后是实体体。状态行表示正在使用HTTP1.1,连接一切正常。实体体部分是报文的主要部分,即它包含了所请求的对象本身(表示为data data data data data…)。

Connection首部行告诉客户,发送完报文后将关闭该TCP连接。Date首部行指示服务器产生并发送该响应报文的日期和时间。Server首部行指示该报文是由一台Apache Web服务器产生的,它类似于HTTP请求报文中的User-agent首部行。Last-Modified首部行指示了对象创建或者最后修改的日期和时间。Content-Length:首部行指示了被发送对象中的字节数。Content-Type首部行指示了实体体中的对象是HTML文本

1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Connection : 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 data data data data ...)

Web站点希望识别用户身份或者限制用户访问的时间或者将用户访问的内容同用户身份相关联,为此使用了Cookie技术。其一般用于标识某个用户。用户首次访问一个站点时,可能需要提供一个用户标识(可能是名字)。在后继会话中,浏览器向服务器传递一个 cookie首部,从而向该服务器标识了用户。因此cookie可以在无状态的HTTP 之上建立一个用户会话层。

Cookie技术包含4个组件:

  • HTTP响应报文里增加一个关于Cookie的首部行;
  • HTTP请求报文里增加一个关于Cookie的首部行;
  • 用户端系统保留一个Cookie文件,由浏览器保存维护:用户每请求一个Web页面,浏览器就会查询cookie文件并抽取她对这个网站的识别码,并放到HTTP请求报文中包括识别码的cookie首部行中
  • Web站点建立Cookie和用户身份的关联,组成数据库;

Cookie

Cookie的使用存在争议,侵犯隐私等

5. Web缓存

Web缓存器也被称为代理服务器,它代表初始web服务器来满足HTTP请求。它有自己的存储空间,并在存储空间里保持有最近请求过的对象的副本;可以通过配置浏览器,将所有指向初始服务器的请求首先指向代理服务器

使用代理服务器,浏览器请求对象的过程:

  • 浏览器创建一个到Web 缓存器的TCP连接,并向Web缓存器中的对象发送一个HTTP请求。

  • Web缓存器进行检查,看看本地是否存储了该对象副本且是否过期。如果有,Web缓存器就向客户浏览器用HTTP响应报文返回该对象。

  • 如果Web 缓存器中没有该对象或者过期,它就打开一个与该对象的初始服务器的TCP连接并发送对该对象的HTTP请求。在收到该请求后,初始服务器向该Web缓存器发送具有该对象的HTTP响应。

  • 当Web缓存器接收到该对象时,它在本地存储空间存储一份副本,并向客户的浏览器用HTTP 响应报文发送该副本。

Web缓存器通常由ISP购买并安装。例如,一所大学可能在它的校园网上安装一台缓存器,或者,一个主要的住宅ISP可能在它的网络上安装一台或多台Web缓存器。

使用代理服务器的优点

  • 减少对客户请求的响应时间(一般,客户与初始服务器之间的瓶颈带宽远低于客户与Web 缓存器之间的瓶颈带宽)
  • Web缓存器能够大大减少一个机构的接入链路到因特网的通信量。

值得一提的是,Web缓存器上存放的对象大多是热点内容

代理服务器

6. 条件GET方法

Web缓存有个问题是缓存器中的对象副本有可能是旧的,条件GET方法可以保证缓存器不断更新对象。

条件GET请求报文的特点:

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

起初原始Web服务器向Web缓存器发送的响应报文中会有一行:Last-Modified: xxxxx,即缓存器在存储该对象时也存储了最后修改日期。隔一段时间后,Web服务器上的该对象可能已经被修改了,该缓存器通过发送一个条件GET 执行最新检查。If-Modified-Since: xxxxx,该条件GET报文告诉服务器,仅当自指定日期之后该对象被修改过,才发送该对象

下面这段响应报文是对象未修改的情况,不用发送对象,其中有Not Modified字样

1
2
3
4
HTTP/1.1 304 Not Modified
Date: sat,10 Oct 2015 15:39:29
server: Apache/1.3.0 (Unix)
( enpty entity body)

(FTP文件传输没写,看以后会不会用到吧,第七版的书里没写)

三、因特网中的电子邮件

1. 电子邮件应用概况

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

  • 用户代理一般是邮件软件或网页。

  • 邮件服务器形成了电子邮件体系结构的核心。每个接收方在其中的某个邮件服务器上有一个邮箱( mailbox )。邮箱管理和维护着发送给他的报文。

  • SMTP是因特网电子邮件中主要的应用层协议。

2. SMTP

SMTP是因特网电子邮件中主要的应用层协议。它使用TCP可靠数据传输服务,SMTP也有两个部分:客户端和服务器端。它限制所有邮件报文的体部分(不只是其首部)只能采用简单的7比特ASCII表示(可读性强)。

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

(1)Alice调用她的邮件代理程序并提供 Bob的邮件地址,撰写报文,然后指示用户代理发送该报文。

(2)Alice的用户代理把报文发给她的邮件服务器,在那里该报文被放在报文队列中。

(3)运行在Alice的邮件服务器上的SMTP客户端发现了报文队列中的这个报文,它(在25号端口)创建一个到运行在 Bob的邮件服务器上的SMTP服务器TCP连接

(4)在经过一些初始SMTP握手后,SMTP 客户通过该TCP连接发送Alice的报文。发送结束后,会关闭TCP连接。

(5)在Bob的邮件服务器上,SMTP 的服务器端接收该报文。Bob的邮件服务器然后将该报文放入Bob的邮箱中。

(6)在Bob方便的时候,他调用用户代理阅读该报文。

email

SMTP一般不使用中间邮件服务器发送邮件,即使这两个邮件服务器位于地球的两端也是建立直接相连的TCP连接

如果Bob的邮件服务器没有开机,该报文会保留在 Alice 的邮件服务器上并等待进行新的尝试,这意味着邮件并不在中间的某个邮件服务器存留

SMTP 用的是持续连接:如果发送邮件服务器有几个报文发往同一个接收邮件服务器,它可以通过同一个TCP 连接发送这些所有的报文。

SMTP与HTTP的对比:

相同点:

  • 持续的HTTP和 SMTP都使用TCP持续连接

不同点:

  • SMTP是一个协议(发送邮件服务器把文件推向接收邮件服务器),HTTP是一个协议(用户从服务器拉文件过来)
  • SMTP要求采用7比特ASCII表示,HTTP没有这种要求
  • SMTP把所有报文对象放在一个报文中,HTTP把每个对象封装到它自己的HTTP响应报文

3. 邮件报文格式

邮件报文格式由两部分组成:

  • 一个包含环境信息的首部:首部行的格式为关键字:value,每个报文的首部行必须包含一个From和To首部行,首部也可以包含其它信息,比如Subject等
1
2
3
From: alice@crepes.fr
To:bobhamburger.edu
Subject: Searching for the meaning of life.
  • 一个包含邮件内容的报文体:用ASCII格式

首部在报文体之前,中间用空行分开。

4. 邮件访问协议

接收方用户的用户代理并不是一直在线,而是访问存储在总是保持开机的共享邮件服务器上的邮箱。该邮件服务器与其他用户共享,并且通常由用户的ISP进行维护(如大学或公司)。

再次审视 Alice给Bob发送邮件的过程:Alice的用户代理可以通过SMTP直接向Bob的邮件服务器发送报文。然而,一般需要通过发送方的邮件服务器作为中转,因为不通过 Alice的邮件服务器进行中继,Alice的用户代理(用户代理也不会一直在线)将没有任何办法到达一个不可达的接收服务器(即这个接收服务器不在线)。这样首先将邮件存放在自己的邮件服务器中,Alice的邮件服务器可以重复地尝试向Bob的邮件服务器发送该报文,如每30分钟一次,直到 Bob 的邮件服务器变得运行为止。简言之,用户代理不可能一直在线,需要发送和接收方有两个服务器作为中转

下面的核心问题就是接收方如何得到接收邮件服务器的邮件?不能使用SMTP得到报文,因为取报文是一个拉操作,而 SMTP 协议是一个推协议。这时就要引入邮件访问协议来解决这一问题

目前有一些流行的邮件访问协议,包括第三版的邮局协议(Post Office Protocol-Version 3, POP3)、因特网邮件访问协议(Internet Mail Access Protocol, IMAP) 以及HTTP

丰富SMTP小节中的图如下:

email1

4.1 POP3

POP3是一个非常简单的协议,因为简单,所以功能有限,POP3使用端口110来建立TCP连接。

POP3按照三个阶段进行工作:

  • 特许:用户代理发送密码和用户名,进行身份鉴别
  • 事务处理:分为两种工作模式,还可以统计邮件信息
    • 下载并删除:用户在一台设备上查看了邮件(下载了邮件)后,邮件将被删除。带来的问题是:在其他设备上将无法查看邮件
    • 下载保留:用户下载邮件后,邮件还在服务器上
  • 更新:用户退出后,POP3结束会话,删除被标记的邮件

4.2 IMAP

用户更喜欢使用一个在远程服务器上的层次文件夹,这样他可以从任何一台机器上对所有报文进行访问。POP3做不到这一点,IMAP可以解决,它是一个邮件访问协议,比POP3要复杂的多,有更多的功能

IMAP将每一份邮件和一个文件夹联系起来,允许用户在不同文件夹里移动邮件并且查询邮件,IMAP服务器维护了IMAP会话的用户状态信息(IMAP是有状态的,POP3是无状态的

IMAP协议还允许用户代理获取报文组件而不是报文整体(用户可能并不想取回他邮箱中的所有邮件尤其要避免可能包含如音频或视频片段的大邮件。)

4.3 基于Web的电子邮件(HTTP)

越来越多的用户使用他们的 Web浏览器收发电子邮件,用户代理就是普通的浏览器。此时用户代理和各自邮件服务器之间使用的协议是HTTP(一拉一推),而发送方邮件服务器和接收方邮件服务器之间使用的协议仍然是SMTP

四、DNS 域名系统

1. DNS概述

识别主机有两种方式:通过主机名(www.google.com)或者IP地址(121.7.106.83)。人们喜欢便于记忆的主机名标识方式,而路由器则喜欢定长的、有着层次结构的IP地址。
域名系统(Domain Name System,DNS)的主要功能:进行主机名到IP地址的转换 。严格来讲,DNS是:

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

DNS协议运行在UDP之上,使用53号端口,它也是应用层协议,它常常被其他应用层协议所使用,包括HTTP、SMTP和 FTP。但和它们不同的是,DNS 不是一个直接和用户打交道的应用,它是为因特网上的用户应用程序以及其他软件提供将主机名转换为其背后的IP地址的功能。DNS采用位于网络边缘的客户和服务器实现主机名到IP地址转换的功能,再次印证了因特网体系结构的复杂性大多数位于网络的“边缘”。

以浏览器请求URL: www. someschool. edu/index. html 为例,为了使用户的主机能够将一个 HTTP请求报文发送到Web服务器www.someschool. edu,该用户主机必须获得服务器的IP地址。其做法如下:

  • 同一台用户主机上运行着DNS应用的客户端(一般是系统自带)
  • 浏览器从上述URL 中抽取出主机名www. someschool. edu,并将这台主机名传给DNS的客户端
  • DNS客户向 DNS服务器(一般就位于主机附近,时延不会太长)发送一个包含主机名的请求。
  • DNS客户最终会收到一份回答报文,其中含有对应于该主机名的P地址。
  • 一旦浏览器接收到来自DNS 的IP地址,它能够向位于该IP地址80端口的HTTP服务器进程发起一个 TCP连接。

DNS还提供以下服务:

  • 主机别名:有着复杂主机规范名(便于管理,可能为:relay1. west-coast. enterprise. com)的主机能拥有一个或者多个别名(便于记忆,www. enterprise.com)
  • 邮件服务器别名:同上(规范主机名可能为:relay1. west-coast. hotmail. com,别名可能为:www.hotmail. com)
  • 负载分配:DNS也用于在冗余的服务器之间进行负载分配。

2. DNS分布式设计

DNS采用分布式的设计方案,单一的DNS服务器无法解决单点故障、通信容量小以及无法临近所有的查询主机和维护困难等问题。

DNS服务器采用层次式组织,并且分布在全世界范围内;大致来说,存在三种DNS服务器:

  • DNS服务器:全世界有400多个根DNS服务器遍及,由13个不同的组织管理。
  • 顶级域(Top-Level Domain, TLD)DNS服务器:每个顶级域(如com、org、net、edu和 gov)和所有国家的顶级域(如uk、fr、ca和jp),都有TLD 服务器(或服务器集群)
  • 权威DNS服务器:通常由一个组织结构维护,记录着公共可访问主机的DNS记录

3. 本地DNS服务器

每个ISP都有一台本地DNS服务器(也叫默认名字服务器)。它不属于该服务器的层次结构,但它起着代理的作用。当主机发出DNS请求时,该请求被发往本地 DNS服务器(对于某居民区ISP来说,本地 DNS 服务器通常与主机相隔不超过几台路由器),并将该请求转发到 DNS 服务器层次结构中。

具体的步骤可以看下图,其中1246都是发送查询DNS报文,3578都是回答DNS报文。这是默认顶级域DNS服务器知道用于主机的权威DNS 服务器的IP地址。一般而言,这种假设并不总是正确的。相反,顶级域服务器只是知道中间的某个 DNS服务器,该中间DNS 服务器依次才能知道用于该主机的权威 DNS服务器。

图中涉及到了两种查询方式:

  • 递归查询:以自身的名义请求DNS
  • 迭代查询:DNS不是返回给请求主机本身

DNS

DNS缓存

为了改善时延性能并减少在因特网上到处传输的DNS报文数量,DNS 广泛使用了缓存技术。即DNS本地服务器将经他请求过的主机和IP映射缓存在本地存储器中,便于其他主机请求相同的映射。

由于主机和主机名与IP地址间的映射并不是永久的,DNS服务器在一段时间后(通常设置为两天)将丢弃缓存的信息。因为缓存,除了少数 DNS查询以外,根服务器被绕过了。

4. DNS记录和报文

暂时跳过

五、P2P文件分发

上述应用(包括Web、电子邮件和 DNS)都采用了客户–服务器体系结构,极大地依赖于总是打开的基础设施服务器。

使用P2P体系结构,对总是打开的基础设施服务器没有依赖,成对间歇连接的主机之间相互通信

对于客户-服务器体系结构,随着对等方数量的增加,分发时间呈线性增长并且没有界。

对于P2P体系结构,最小分发时间不仅总是小于客户-服务器体系结构的分发时间,并且对于任意的对等方数量N,总是小于1小时。

因此,具有P2P体系结构的应用程序能够是自扩展的。这种扩展性的直接成因是:对等方除了是比特的消费者外还是它们的重新分发者。

有两种典型因特网应用十分适合P2P体系结构:

  • P2P文件分发(BitTorrent是一种用于文件分发的P2P协议)

  • 分布式散列表:布式散列表是一种简单的数据库,其数据库记录分布在一个P2P系统的多个对等方上。

六、视频流和内容分发网

视频流:在流式存储视频应用中,基础的媒体是预先录制的视频,放置在服务器上,用户按需向这些服务器发送请求来观看视频。普遍采用HTTP流,它具有严重缺陷,即无论带宽大小,所有客户接收到相同编码的视频

DASH(Dynamic AdaptiveStreaming over HTTP,经 HTTP的动态适应性流):视频编码为几个不同的版本,其中每个版本具有不同的比特率,对应于不同的质量水平。客户根据自身带宽动态地请求不同版本的视频流

内容分发网:(Content Distribution Network,CDN),CDN分布在多个地理位置上的服务器,在它的服务器中存储视频(和其他类型的Web内容,包括文档、图片和音频)的副本,用于提供更好的用户体验。

七、套接字编程

典型的网络应用是由一对程序(即客户程序和服务器程序)组成的,它们位于两个不同的端系统中。当运行这两个程序时,创建了一个客户进程和一个服务器进程,同时它们通过从套接字读出和写入数据在彼此之间进行通信。开发者创建一个网络应用时,其主要任务就是编写客户程序和服务器程序的代码。

1. UDP套接字编程

UDP server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# -*- coding: utf-8 -*-

# @File : UDPserver.py
# @IDE : PyCharm
# @Date : 2021-05-07
# @Author : wy

from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('', serverPort))
'''
将端口号12000与服务器的套接字绑定,当有人向该服务器的端口12000发送分组时,
该分组将导向该套接字,UDPserver进入一个while循环,等待接受并处理来自客户的分组
'''
print("The server is ready to receive")

while True:
message, clientAddress = serverSocket.recvfrom(2048)
modifiedMessage = message.decode().upper()
print(modifiedMessage,clientAddress)
serverSocket.sendto(modifiedMessage.encode(),clientAddress)

UDP client.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# -*- coding: utf-8 -*-

# @File : UDP client.py
# @Date : 2021-05-07
# @Author : wanyu

from socket import *
serverName = '10.112.52.59' # 服务器虚拟机wanyu的地址
serverPort = 12000

clientSocket = socket(AF_INET, SOCK_DGRAM) # 第一个参数是选择为IPV4地址,第二个参数是选择为UDP
message = input('Input lowercase sentence:') # 获取键盘输入

'''
这里是UDP的特殊之处,即UDP在将分组丢进套接字之前必须为其附上一个目的地址
'''

# UDP的发送函数是sendto,需要附上目的地址
clientSocket.sendto(message.encode(), (serverName, serverPort)) # 将键盘输入的字符串类型转为字节类型,
# sendto函数为报文附上目的地址

# UDP的接收函数是recvfrom,可接收另一端地址
modifiedMessage, serverAddresss = clientSocket.recvfrom(2048) # 分组数据放到变量modifiedMessage中,
# 源地址放到serverAddresss中,缓存长度选择为2048

print(modifiedMessage.decode())
print(serverAddresss)
clientSocket.close() # 关闭连接

2. TCP套接字编程

TCP server.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# -*- coding: utf-8 -*-

# @File : TCP server.py
# @Date : 2021-05-07
# @Author : wy

from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM) # IPV4 TCP
serverSocket.bind(('', serverPort))
serverSocket.listen(1) # 欢迎套接字等待并聆听某个客户敲门,参数是连接的最大数,至少为1
print("The server is ready to receive")
while True:
connectionSocket, addr = serverSocket.accept() # 客户敲门时,调用accept方法,创建一个新的连接套接字,给这个客户专用
sentence = connectionSocket.recv(2048).decode()
capitalizedSentence = sentence.upper()
print(capitalizedSentence, addr)
connectionSocket.send(capitalizedSentence.encode())
connectionSocket.close()

TCP Client.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# -*- coding: utf-8 -*-

# @File : TCP Client.py
# @Date : 2021-05-07
# @Author : wanyu

from socket import *
serverName = '10.112.52.59' # 服务器虚拟机wanyu的地址
serverPort = 12000

clientSocket = socket(AF_INET, SOCK_STREAM) # 第一个参数是选择为IPV4地址,第二个参数是选择为TCP

'''
TCP的特殊之处在于:发送数据之前,要先建立起TCP连接
'''
clientSocket.connect((serverName, serverPort)) # 发起TCP连接,执行三次握手,建立完成客户到服务器之间的TCP连接

sentence = input('Input lowercase sentence:')

# TCP的发送函数是send,无需附上目的地址
clientSocket.send(sentence.encode()) # 通过客户的套接字进入TCP连接发送字符串,无需附上目的地址

# TCP的接收函数是recv,无需接收另一端地址
modifiedSentence = clientSocket.recv(2048) # 接收来自服务器的字节,分组数据放到变量modifiedSentence中,缓存长度2048

print('From Server:', modifiedSentence.decode())
clientSocket.close() # 关闭连接

《计算机网络:自顶向下方法》笔记:02.应用层
http://jswanyu.github.io/2022/04/05/Network/《计算机网络:自顶向下方法》笔记:02.应用层/
作者
万宇
发布于
2022年4月5日
许可协议