《计算机网络:自顶向下方法》学习笔记第二章

应用层

2.1网络应用原理

研发网络应用程序的核心是能写出能够运行在不同端系统和通过网络实现彼此间通信的程序。

应用层写应用软件时不需要考虑网络核心的软硬件,这种将应用软件限制在端系统的方法促进了网络应用程序的迅速研发。

2.1.1网络应用体系结构

网络体系结构是固定的,并为程序提供了特定的服务集合。应用体系结构由程序员设计,规定了如何在不同的端系统运行程序。在选择应用体系结构时,常用的两种主流结构是用户-服务器结构P2P(对等)体系结构

在客户-服务器结构中,有一个总是打开的主机叫做服务器,服务于许多其他被称为客户的主机。典型的就是Web应用,有一个web服务器一直处理来自用户主机上的浏览器的服务请求。

客户-服务器结构下,客户端和客户端之间是不会直接通信的。而且在该模式下服务器具有特定的不变的IP地址而且是总是运行着的,所有客户总是能通过服务器的IP地址与其建立连接。由于服务器需要处理大量的服务请求,所以经常会使用托管大量主机的数据中心来创建强大的虚拟服务器,尤其在一些知名的互联网企业。

P2P结构中,客户对于服务器基本上无依赖,应用程序在间断连接的主机直接直接通信,通信双方叫做对等方。这种通信方式不需要经过服务器,因此任意对等方都不为服务器提供商所有。

P2P一个很突出的特定就是其自扩展性,在一个P2P文件共享程序中,虽然任意对等方之间的文件传输都会造成工作负载,但是任意对等方通过其他对等方分发文件也都会扩展程序的服务能力。而且P2P结构不需要庞大的服务器和带宽,但是可能会由于高度非集中式架构造成安全性,可靠性和性能上的隐患。

2.1.2进程通信

通信时,实际上是不同端系统的进程进行通信

一个进程就是一个在端系统上运行的程序,当多个进程运行在端系统时,可以通过进程间的通信机制相互通信。进程间的通信规则由操作系统进行规定。

而对于不同端系统的进程,其通信需要跨越网络交换报文实现通信。

1.客户和服务器进程

网络应用程序由成对的进程组成,这些进程相互发送报文,我们将这两个进程成为服务器进程和客户进程,请求建立连接的是客户进程,被建立连接的就是服务器进程。

2.进程和计算机网络之间的接口

不同端系统的进程通信需要经过网络,进程通过套接字(socket)软件接口向网络发送和接收报文。可以将socket理解为插头或者插座,插座可以传输电源,插头用于接收电力,并且其一一对应。

套接字是主机内应用与运输层之间的接口,由于套接字是建立网络应用程序的可编程接口,因此套接字也被称为是应用编程接口。开发者可以控制几乎套接字在应用层的一切,但对于底层的运输断基本上没用权限。开发者的控制基本上限于:选择运输层协议,设定一些运输参数如最大缓存,最大报文段长度等

3.进程选址

为了向特定主机的特定进程发送分组,需要提供接收进程的地址,包括两部分,一个是对应端系统的IP地址还有对应进程在对应端系统的端口号

在因特网中,主机由一个32bit大小的IP地址标识,而在主机内不同的进程则也对应一个端口号用作标识。

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

1.可靠数据传输

有一些应用和常见是不能容许数据的丢失的,必须做到数据的0丢失,如金融应用,因此运输层必须设定一个能实现对应要求的数据传输协议,这种协议就具有可靠数据传输的功能,即能够确保由应用程序一端发送的数据正确的交付到该应用程序的另一端

而当运输层协议不提供可靠数据传输服务时,他通常是用于可容忍数据丢失的应用,如多媒体,游戏之类

2.吞吐量

在进程通信时,发送进程能够交付为接收进程的比特的速率就是有效吞吐量。通常会随时间波动,运输层的某个协议能够保证以一个特定的速率传输数据,确保稳定的可用吞吐量,可以保证数据传输的稳定,具有吞吐量要求的应用也叫带宽敏感 的应用,相对应的就是弹性应用。

3.定时

运输协议可以规定数据运输所需的时间

4.安全性

运输协议可以提供多种安全性服务

2.1.4因特网提供的运输服务

因特网为应用程序提供了两个传输协议:TCP与UDP

1.TCP服务

TCP协议是面向连接可靠数据传输的服务,在报文传输之前,客户端和服务器端需要先建立连接。

面向连接:TCP让客户端和服务器端相互交换控制信息(握手),这个握手过程就是提醒双方建立连接并开始传输和接收数据。这条连接是全双工的,也就是双方都可以同时收发报文,当结束时也需要通过握手来断开连接。

可靠的数据传输:通信进程可以信赖TCP,无差错、按顺序的传输数据。

TCP还有拥塞控制协议,当接收方或发送方出现拥塞,TCP会抑制进程从而缓解拥塞,同时TCP还会自动控制每个连接的速率,从而尽可能的实现资源的平均分配

TCP不包含网络安全的服务,但是TCP的加强版运输层安全协议(TLS)实现了网络安全服务

2.UDP服务

UDP服务是一种轻量级的服务,是无连接的,不可靠的数据传输协议,同时他也不具有拥塞控制和控制资源分配的功能,但是这也意味着它具有更高的可操作性如实现对用户流量的控制

3.因特网不提供的服务

上述中可以知道因特网的传输层协议提供的可靠数据传输与安全的服务,但是对于定时和吞吐量的服务并未进行讨论,即目前的协议并未提供这两种服务,但并不意味运行时间敏感的应用和吞吐量敏感的应用不能在因特网运行。因为这种应用会在应用程序内对于这两种服务的缺失做出对应的很好的应对方案,但是仍然会有一定的限制。总之就是因特网支持对于定时服务和吞吐量服务有要求或敏感的应用程序的运行,但是它本身是不提供这两种服务的。

2.1.5应用层协议

应用层协议定义了运行在不同端系统上的应用程虚进程如何相互传递报文。

应用层协议规定了以下内容:

  1. 交换报文的类型,例如请求和响应报文
  1. 各种报文的语法,如报文中的各种字段和这些字段都是如何描述的
  2. 字段的语义,即这些字段在报文中的含义
  3. 确定一个应用进程在什么时候以及如何发送报文,对报文的响应规则

有些应用层协议是由RFC文档(请求评论,具体定义见1.1.1)定义的,因此位于公共域中(应用层应用都能使用)如HTTP协议。

值得一提的是网络应用并不是应用层协议,应用层的协议只是网络应用的一部分

2.1.6本书涉及的网络应用

本书会主要讨论Web,电子邮件,目录服务,流式视频以及P2P

2.2Web和HTTP

Web指万维网,它最初最大的特点就是被动的输出信息也就是根据用户的需求输出信息(现在很常见)同时还接入了许多平台的服务如B站,油管,Web所使用的协议就是HTTP协议(超文本协议)

2.2.1HTTP概述

HTTP由两个程序实现,一个客户程序,一个服务器程序分别运行在不同的端系统并通过交换报文实现通信。

Web页面也叫文档,是由对象组成的。一个对象只是一个文件,注入HTML文件、一个JPEG图形,一个JS文件等等,他们可以根据一个URL(统一资源定位符,就是网址)寻址。多数的Web页面都有一个HTML基本文件与几个引用对象。

例如:http://www.someschool.edu/someDepartment/picture.gif,在这个网址,www.someschool.edu就是主机名,/someDepartment/picture.gif就是路径名Web浏览器实现了http的客户端Web服务器实现了服务端。

HTTP协议定义了客户请求Web页面的方式,以及服务器向客户传输Web页面的方式。当用户发送了一个请求报文(包含请求的Web页面所需要的对象),服务器端在收到后就会返回包含这些对象的响应报文。

HTTP协议采用TCP的运输协议,一旦连接建立,服务器进程和客户进程就能通过socket接口访问TCP连接并进行报文的交互,即客户通过套接字传输请求报文和接收响应报文,服务器通过套接字接收请求报文和传输响应报文。对于TCP的信息传输,一旦客户进程发送了连接请求并建立连接,服务器端和客户端之间的报文交互就由传输层的TCP协议自主控制,脱离了应用层的掌控,这也就是分层架构的最大优点,也就是各层之间分工明确且相互影响小(也可以说是耦合小)TCP是可靠的数据传输协议,对于数据的丢失和乱序的数据恢复也是不需要应用层考虑的。

HTTP是一种无状态的协议,也就是服务器端不会记录客户端信息,比如客户端在短时间访问了同一个Web页面两次,服务器不会因为客户端刚刚请求了这个对象就不响应。

HTTP的版本:HTTP的最初版本是HTTP/1.0,目前很多是使用HTTP/1.1,最新的是HTTP/2

2.2.2非持续连接和持续连接

假定客户端在一段时间向服务器端发送了多个请求,可能是连续发送,也可能是周期性的发送,这时从时间和资源分配上,需要考虑是建立多个TCP连接分别发送请求(非持续连接)还是使用一个TCP连接一次性传输所有请求(持续连接)

1.采用非持续连接的HTTP

假定客户端要向服务器端请求一个具有10个JPEG图形和一个HTML的Web页面,且都位于这台服务器上。HTML的URL(网址)是

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

建立连接的过程为:

1. 客户端进程首先通过端口号80(这个是默认的)到服务器端(www.someschool.edu)发起一个TCP连接,在客户端和服务器端都有一个套接字与连接对应

2. 客户端发送一个请求报文,包含路径名(/someDepartment/home.index)

3. 服务器端通过套接字接收请求报文,检索出路径,在一个响应报文中封装好对象发送给客户端进程

4. 服务器端通知断开连接(发送报文)

5. 客户端收到响应报文并关闭连接从HTML文件中获取对JPEG图形的引用

6. 然后根据引用,重复步骤1-4向服务器请求每一个JPEG 图形

由此,资源已经请求完毕,至于怎么显示给用户,需要看浏览器对应如何规定,与HTTP无关

对应非持续连接的HTTP,每次TCP连接只会传输一个对象,然后连接就会关闭。所以一共产生了11次TCP连接。不过对于后面十次的请求图形的连接,因为我们在第一次连接时已经获得了全部的10个引用,所以可以选择是一次性建立10个TCP连接获取图形还是逐个请求(并行和串行)

往返时间(RTT):是指客户端到服务器端传输一个短分组并返回客户端所需的最短时间,其大小与时延有关,通常用于客户端和服务器端通信所需时间的估算。例如在TCP连接时会有一个“三次握手”的过程,就是第一次客户端发送一个短报文请求连接,第二次是服务器发送一个报文确认请求并同意连接,第三次是客户端发送报文确认连接的建立,然后服务器端开始发送文件。第一次和第二次握手相当于一个短报文从客户到服务器再回到客户也就是一个RTT,同样的,从第三次握手到所传输文件的第一个极小的报文到达客户端也是一个RTT。因此我们可以认为在传输文件之前花费了两个RTT建立连接,所以总时间就是两个RTT加上传输文件所需要的时间(短报文的大小忽略不计)

2.采用持续连接的HTTP

非持续连接的缺点显而易见,一是必须为每一个请求对象建立并维护一个连接,会给服务器带来巨大的负担,二就是每次建立连接时都会花费两个RTT的时间,如果对象特别多且采用串行的方式,会产生巨大的额外的时间开销。所以我们也能由此推出持续连接的HTTP协议的优点。

2.2.3HTTP报文格式

HTTP规范包含两种HTTP报文格式:请求报文和响应报文

1.HTTP请求报文

例:

虽然只有五行,但是实际的请求报文可能有任意多行(至少1行)

第一行叫做请求行,后继的行是首部行

请求行有三部分,方法字段,URL字段和HTTP版本字段。方法字段可以取几种不同的值,包括GET、POST、HEAD、PUT 和DELETE。本例中方法字段是GET,请求对象的URL,版本是1.1

接下来是首部行,首先第二行指明了对象所在的主机,虽然已经建立了连接,但是还是需要指明主机,用于缓存数据。第三行的意思是不使用持续连接。第四行的意思是请求的浏览器的类型,用于有效的为不同类型的用户代理发送对象的不同版本。最后一行是代表语言。

下面是请求报文的一个通用格式,在实体体部分,如果使用GET方法则实体体为空,使用POST方法时才会使用该实体体,通常是HTTP用户提交表单时会用到。例如在搜索“深圳大学”时,用户使用POST方法,此时实体体内就是“深圳大学”服务器会返回一个代表搜索结果的Web页面。但是用表单生成的请求报文不一定都是使用POST方法。

HTML表单经常使用GET方法,通常在URL中进行扩展包括所输入的数据。例如输入“S”“Z”,URL可能就是www.somesite.com/city?S&Z

HEAD方法于GET类似,服务器收到HEAD类型的请求时会使用HTTP报文响应但不返回对象,常常用于调试跟踪。

PUT方法常常于Web的发行工具一起使用,允许用户向服务器上传对象到指定的路径。

DELETE用于用户删除对象

2.HTTP响应报文

这是一个典型的HTTP响应报文,有三个部分,一个初始状态行,6个首部行,然后是实体体实体体是报文的主要部分,包含了请求的对象本身

状态行表示服务器正在使用HTTP/1.1一切正常,第二行表示发送后关闭TCP连接,第三行表示发送报文的时期,这个时期是服务器将响应报文发送出去的时刻。然后下一行是代表服务器的类型,第五行是对象最后修改日期,然后下一行是对象的字节数,最后一行是实体体对象的类型,这里表示实体体对象的HTML文本。

这个是响应报文的通用格式,一些常见的状态码和短语如下:
200 OK:请求成功,信息在返回的响应报文里面

301 Moved Permanently:请求的对象被永久转移,新的URL定义在报文里面的Location里,客户会自动获取。

400 Bad Request:指令不能被服务器理解

404 Not Found:请求的文档不在服务器上

505 HTTP Version Not Support:服务器不支持该HTTP版本

可以用Talnet登录到一个Web服务器上试着发送报文。

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

注:这部分内容写的比较简陋,可以在原书p70详细查看cookie的工作流程

HTTP是无状态的协议,但是Web站点通常会希望能够识别用户,比如用来限制用户访问,因此HTTP使用了cookie,它允许站点对用户进行跟踪。

Cookie有四个组件:1.在HTTP响应报文中的一个cookie首部行;

2.在HTTP请求报文中的一个cookie首部行;

3.用户端系统保存的一个cookie文件并由浏览器管理;

4.web站点的一个后端数据库。

Cookie可以用于标识一个用户,用户首次访问一个站点时可能需要提供一个用户标识(可能是名字)后续会话中浏览器向服务器传递一个cookie首部使得服务器标识该用户。因此cookie可以在HTTP的无状态协议上建立一个用户的会话层,允许服务器标识用户(引发用户隐私安全问题

2.2.5Web缓存

Web缓存器也叫代理服务器,是能够代表初始Web服务器来满足HTTP请求的网络实体,可以保存用户请求过的对象的副本。可以配置用户的浏览器的HTTP请求先指向缓存器,具体流程就是:
首先,浏览器创建一个到缓存器的TCP连接,并发送HTTP请求

然后,缓存器检测有没有所需对象的副本,有就返回,如果没有,缓存器就打开一个和服务器的TCP连接,发送所需对象的HTTP请求,服务器收到请求后返回响应报文。

最后缓存器接收到对象后会先存储副本,再返回给用户。因此缓存器既是服务器也是客户,通常由ISP购买安装。

部署缓存器的原因有两个,第一,很明显是为了节省响应时间(考虑瓶颈带宽的问题,客户与服务器的瓶颈带宽往往小于客户与缓存器)其次,也是很明显的优点就是减少了服务器所需建立的连接数,减轻服务器的负载。(具体的速率的比较不再举例了)

对于瓶颈链路对数据传输速率的影响的两种解决方案,一种就是直接增加链路的速率,另一种就是通过接入缓存器来优化性能这种网络也叫内容分发网络(CDN)

但是,需要考虑一种情况就是虽然对象被缓存了,但是如果版本不同或者源对象被更新了要怎么区分。HTTP中有应对这个情况的机制:条件GET机制

首先,一个浏览器向服务器发送请求报文,然后服务器向缓存器发送带有对象的响应报文

然后缓存器在转发对象时将对象在本地缓存同时存储了最后修改日期。

一周后,用户重新请求该报文,由于时间不同,缓存器向服务器发送一个条件GET执行最新检查,服务器告诉缓存器在这一周内对象有没有被修改,然后向缓存器发送含有所需对象的(如果被更新了)响应报文

2.2.6HTTP/2

HTTP/1.1中传输的每个web页面共享总的带宽,因此就存在队首阻塞(HOL)假设9个小文件和一个大文件同时传输,如果先传输大文件,小文件的传输的时延就会很大,因为要在大文件传输完才能进行传输,HTTP/1.1的解决办法是采用并行传输的方式。

TCP的拥塞控制机制是为了实现总带宽在不同链路上的平均分配,但是有时候可能会有一个文件的传输会选择同时打开多个并行的连接实现扩大带宽的效果,这明显是不公平的,因此HTTP/2的基本目标之一就是为了摆脱传输单一web网页时的并行TCP连接,不仅减少了所需要的套接字(建立的连接数),也使得TCP能按照其设定之初的目标尽可能实现传播的资源分配的公平性。

1.HTTP/2成帧

HOL的解决方案是将每个报文分成小帧,在TCP连接上交替发送每个报文的帧(类似时分复用)实现在串行连接实现类似并行的效果并且不会影响tcp的资源分配。这一过程是协议的成帧子层实现的,报文发送时把报文拆分成帧再发送,接收时将接收到的帧组合成报文再接收。除此之外成帧子层还会对这些帧进行二进制编码,二进制解析更为高效,会得到更小的帧且不易出错。

2响应报文的优先次序和服务器推

也就是客户向服务器发起请求时,服务器可以根据优先程度对所需的对象的发送顺序进行排序,方法也就是为每个对象分配一个优先权权重(1-256),同时服务器还会自动为客户推送客户可能需要的对象,使得客户只需一个请求报文就能收到多个响应报文,主要是通过服务器分析客户所需要的对象所在的HTML页即可得到客户可能需要的对象

3HTTP/3

QUIC是一种新的运输层协议,再UDP基础上实现,详情见第三章。

2.3因特网中的电子邮件

因特网的电子邮件系统主要有三个组成部分:用户代理,邮件服务器,简单邮件传输协议(SMTP),邮件服务器是邮件系统的核心,每个用户都有一个邮箱负责管理和维护接收到的报文。邮件的发送过程是,邮件从邮箱出发进过服务器到达目的邮箱,用户读取邮件时,服务器会先鉴别身份再交付报文。同时如果邮件发送失败就会放在特定的报文队列里面,每隔一段时间重新发送直到发送成功。

SMTP协议也是再TCP的基础上实现的也是由客户端(发送方)和服务器端(接收方)组成,每个邮件服务器都充当客户和服务器的作用。

2.3.1SMTP

SMTP的基本操作流程:假设是用户Alice要 向BOb发送邮件,首先Alice调用邮件代理程序并提供Bod的邮件地址,撰写邮件并发送。然后Alice用户代理把报文发送到邮件服务器并放在服务器的报文队列里。然后服务区上的客户端检测到这个报文并与Bob的邮件服务器建立连接经过一些初始的SMTP握手将报文发送给Bob的邮件服务器。在Bob的服务器上服务器接收报文并发送给Bob的邮箱,在Bob有时间的时候就能查看到邮件了。

值得一提的,SMTP一般不通过中间邮件服务器发送邮件,只需首尾部的服务器直接发送,例如,Alice的邮件服务区在北极,而Bob的在南极,一般就会直接建立一个从北极直达南极的TCP连接。如果Bob的服务器出现问题不能接收,邮件就会在Alice的服务器存留,并等待新的尝试(发送)

2.3.2邮件报文格式

SMTP邮件报文的都有一个首部,在报文体的前面,一个首部行一定有一个“from:”行和“to:”行,这两个是必须的,还有一些可选的首部行如“subject:”一个标准的报文首部看起来如下:

在首部行后紧接着是一个空白行,然后是ASCII格式的报文体

2.3.3邮件访问协议

如果Alice需要把邮件发给Bob,她可能在任意时间发送,但是Bob未必能够在任意时间接收邮件,如之前所说,Bob想要接收邮件必须要一种保持自己的PC代理服务器在线,这很难实现,所以如果Bob不在线,这个邮件会传导到Bob对应的邮件客户端,客户端会每隔一段时间向Bob的代理服务器发送这个邮件直到它收到邮件。但是Alice的代理服务器和Bob的邮件服务器没有一个直接的SMTP对话,通常是Alice使用HTTP或SMTP将邮件推入自己的邮件服务器由Alice的邮件服务器将邮件发送给Bob的邮件服务器。之所以分为两步来进行,主要是Alice的代理服务器如果不经过邮件服务器不能到达Bob的邮件服务器,而且Alice的邮件服务器接收到邮件时也可以一直向Bob的邮件服务器发送邮件直到对方接收(如果Alice的邮件服务器没有允许,Alice的代理服务器可以直接向系统管理员申告)

但是,像是SMTP这种协议,它属于是一种推的协议,也就是把邮件主动的推送到另一个服务器,Bob的代理服务器想要从他的邮件服务器主动的获取邮件则需要一个拉取邮件的协议也就是拉协议。目前有两种常用的方法解决这个问题,一是如果Bob使用基于Web的邮件程序或者移动客户端,可以使用HTTP协议拉取电子邮件(需要Bob的电子邮件程序有HTTP和SMTP接口);二是使用因特网邮件访问协议(IMAP)通常用于微软的Outlook,HTTP和IMAP都支持用户对邮件的管理移动删除标记等操作。

2.4DNS:因特网的目录服务

因特网也需要规定对主机的标识方式,其中的一种是主机名(hostname),如www.facebook.com,www.baidu.com等等,但是主机名只是提供了一个辨识主机的方法,几乎没有提供主机的位置信息(并不是完全没有)而且主机名可能会比较复杂,路由器难以处理。所以就出现了IP地址,主机可以使用IP来标识

(详情见第四章)IP地址由四个字节组成,例如127.0.0.1(这是回环地址,在一个主机内表示该主机自己的地址)每个字节由一个‘.’分隔开,表示0-256的十进制数字。从左往右进行扫描IP地址可以得到越来越详细的位置信息(具有层次性

2.4.1DNS提供的服务

刚刚我们提到了主机名和IP地址两种标识主机的方法,为了方便,我们需要一个把主机名转变为IP地址的服务,也就是DNS(域名系统)的任务

DNS:是一个分层的DNS服务器实现的分布式数据库;也是一个使得主机能够查询分布式数据库的应用层协议。DNS服务器通常是运行BIND软件的UNIX机器,DNS协议运行在UDP服务之上,使用53号端口。

HTTP,SMTP等其他协议通常都会使用DNS协议提供主机名到IP的映射服务。通常用户在浏览器上请求URL页面,为了发送报文到对应服务器,首先需要解析IP地址:首先需要保证同一台用户主机运行着DNS的客户端,浏览器可以从URL里面提取主机名并传给DNS客户端。然后DNS客户端会给DNS发送包含主机名的请求,服务器会向DNS客户端发送响应报文(其中包含IP地址),浏览器收到来自DNS的响应报文后就可以根据IP地址建立连接传输报文了。

DNS还提供其他的一些服务,比如主机别名,可以为一个名字很复杂的主机起一个或多个便于记忆的别名(当然格式还是一样的),可以通过对主机别名进行DNS解析获取对应IP

还有邮件服务器别名,以及负载分配(通常一个繁忙的站点(如cnn.com)会被分在多个服务器上,每个服务器运行在不同的端系统也具有不同的IP,这时候一个主机名就可能对应多个IP,DNS将这些IP统一起来变为一个IP集合,把主机名映射为这个IP集合,对用户名进行解析时会有整个IP集合进行响应,而为了平均分配资源和负载(因为用户总是会访问在集合中排的靠前的IP,会导致不同服务器负载不均衡)DNS会使这些服务器轮流响应,同样也能用于邮件服务器)等

2.4.2DNS工作机理概述

从用户主机上调用应用程序的角度来看,DNS可以看成是一个提供将主机名转为为IP的服务的黑盒子,但是再DNS中实现这个服务是非常复杂的。

DNS最简单直接的设计方式是在因特网上面只使用一个DNS服务器,包含所有主机名到IP的映射,与所一用户直接连接,直接为用户提供服务(很显然是不可行的),这个设计方式的问题如下:

1.单点故障,一旦这个DNS服务器崩溃,所有的网络都会崩溃

2.通信容量,这一个DNS服务器需要处理全球数十亿甚至百亿台主机的请求

3.维护,一个全球性的服务器必然无比庞大,不仅要为所有的主机保留记录还需要应对主机信息的更新

4.远距离的集中式数据库,单个DNS数据库不可能靠近所有用户,这可能会导致严重的时延

很明显,在单个DNS服务器上使用集中式数据库管理用户数据的方式完全没有可扩展能力,由此我们采用分布式数据库

1.分布式、层次数据库

DNS使用了大量的服务器分布在世界各处,主要有3种DNS服务器:根DNS服务器,顶级域(TLD)DNS服务器和权威DNS服务器下面是部分DNS服务器的层次结构

根DNS服务器:有很多根DNS服务器遍布世界,这些根服务器是13个不同根服务器的副本,由12个不同组织管理,负责提供TLD服务器的IP地址

TLD(顶级域)DNS服务器:对于每个顶级域和国家的顶级域(如com、net、ca、cn)都有TLD服务器集群,由特定公司负责维护,TLD服务器提供了权威DNS服务器的IP

权威DNS服务器:在因特网上具有公共可访问主机(如Web服务器)的组织机构都需要提供公共可访问的DNS记录,这些记录将主机名映射为IP地址,组织机构的权威服务器会收藏这些记录。

还有一类更重要的DNS服务器叫做本地DNS服务器,但它不属于DNS服务器的层次架构。一般每个ISP都会有一个本地的DNS服务器,当主机连入ISP时,ISP会提供一个主机的IP,该主机具有多个本地ISP的IP地址,主机的本地DNS服务器通常邻近主机。本地DNS服务器大多数起到代理的作用,用户会先将请求发送到本地DNS服务器,由本地DNS服务器连入DNS服务器层次结构。

比如主机先向本地DNS服务器发送包含主机名的DNS查询报文,本地DNS服务器接收到之后会向根服务器转发该报文,根服务器会根据这个报文来告诉本地服务器需要向哪个TLD DNS服务器查找(返回一个TLD服务器的IP地址列表),本地服务器再根据这个列表在这些TLD DNS服务器之一中发送查询报文。TLD查询到之后会用权威DNS服务器的IP进行响应(也可能是一个中间DNS服务器,因为TLD服务器不一定知道权威服务器的IPt),本地服务器重新向权威服务器发送查询报文并获得来自权威服务器的IP映射。这个过程一共发送了4份查询报文(1 2 4 6)和4个回答报文(3 5 7 8),可以通过缓存来降低流量

上图可以看到本地DNS服务器分别向根DNS服务器查询后返回,再向TLD DNS服务器查询,再向权威DNS服务器查询,这种迭代进行查询的方式就是迭代查询,相应的,还有递归查询,如下

2.DNS缓存

DNS缓存的原理很简单,再一个请求中,当本地DNS服务器接收到一个主机对应的IP的解析的回答后,就会将这个映射缓存在本地,下次用户如果再查询这个主机就可以直接做出响应。

2.4.3DNS记录和报文

共同实现DNS分布式数据库的所有DNS服务器实现了资源记录(RR),RR提供了所有主机名到IP的映射,资源记录是一个包括了下列字段(Name,Value,Type,TTL)的四元组

TTL是该记录的生存时间,决定了资源记录什么时候从缓存删除Name和Value的意义取决与Type。

如果Type=A,则对主机而言Name是主机名,Value是IP,这个资源记录就是一个主机名到IP的映射

如果Type=NS,则Name就是域,Value就是一个知道如何获得该域中主机IP地址的权威DNS服务器的主机名

如果Type=CNAME,Value就是主机别名Name对应的规范主机名。

如果Type=MX,Value是邮件服务器别名为Name对应的规范主机名

如果一个DNS服务器是一个主机的权威服务器,他就会有一个Type=A的资源记录该主机主机名到IP的映射;如果不是,那就会有一个NS类型的记录记录包含该主机名的域,还有一个类型为A的记录,记录提供了在NS记录的Value服务器的IP

1.DNS报文

DNS只有查询和回答报文两种且具有一样的格式

前12字节是首部区域,第一个字段是标识符,是一个16bit数用于标识该查询,会被复制到对应的回答报文,以便用户用它来匹配请求和回答。1bit的标准位代表这个报文是查询报文(0)还是回答报文(1)。如果某DNS服务器是所求的权威服务器时会在回答报文中有1bit的“权威的”标志位。如果不希望进行递归查询,就会设置一个1bit的“希望递归”标志位,反之则在对应位置做标志。还有四个与数量有关的字段,分别代表对应在数据区域出现的数量

问题区域包含查询的问题,包括名字字段(正在被查询的主机名)类型字段

回答区域包含了对请求的问题的资源记录,可能会有多个记录,也就是说一个主机可能对应多个IP

权威区域包含了其他权威服务器的记录

附加区域是一些可能会有帮助的记录

2.在DNS数据库中插入记录

如果要注册域名时,首先要向对应的机构提供你的基本的辅助权威DNS服务器的名字和IP,对应这两个权威DNS服务器,机构会采用一个NS类型和一个N类型的资源记录输入TLD服务器。你还需要确保用于Web服务器的类型A资源记录和用于邮件的MX记录被输入到你的权威服务器里面,然后人们就能访问你的站点了。

2.5P2P文件分发

前面有讲过使用P2P的体系结构对基础设施依赖小,本节对于P2P的介绍主要以BitTorrent协议为例(这是目前最流行的P2P协议)

2.5.1P2P体系结构的扩展性

如上图,us表示服务器接入链路的上传速率,ui表示第i对等方接入联络的上传速率,di表示第i对等方的下载速率,F表示被分发的文件的总长度,N表示要获得该文件的副本的对等方的数量。分发时间就是N个对等方得到该副本所需的时间,记为Dcs。以下我们假设互联网核心拥有足够的带宽,所有的瓶颈链路都在接入网,还假设用户和服务器的所有带宽都用于分发该文件。

如果没有对等方互相传输文件,服务器向N个客户传输文件所需时间就是NF/us,dmin是最小的下载速率(N个用户的下载速率里面的最小值)则最小分发时间为F/dmin

所以Ds>=max{F/dmin,NF/us}。此时如果对于足够大的N,很容易看出分发时间会变得极大,而如果使用P2P的体系结构,最小分发时间是可以大大优化的(具体见书P92)尤其是当N特别大是,这两种模式的分发时间随N的增长分别成线性和对数增长,如下

P2P结构下,最小分发时间不仅一直小于客户-服务器结构,而且还一直小于1h(无论N的大小)由此我们说P2P具有良好的自扩展性,原因就是因为对等方不仅是文件的消费者而且也变成了文件的传输者。

2.5.2BitTorrent

这是一种流行的P2P协议,协议定义,参与一个特定文件分发的所有对等方的集合叫做一个洪流,在一个洪流中的对等方下载相同大小的文件块,典型 的块长度为256KB,对等方首次加入洪流时没有块,加入的时间越久,积累的块就越多。当他获得了整个文件,他可能会离开洪流或者在洪流里面继续传输块,当然也可能在只一块子集的情况下离开洪流或者再次加入洪流。

在每个洪流里面都有一个追踪器,对等方加入洪流时向追踪器注册并周期性的告诉追踪器自己仍然在洪流里面,由此追踪器能够追踪对等方。当一个新的对等方加入洪流时,追踪器会随机的抽取一个对等方的集合并将这个集合的一个子集中的对等方的IP发送到新对等方,新加入的对等方可以根据这个IP列表建立TCP连接与其成为临近对等方,由于对等方的加入和离开,邻近对等方也会不断变化。

在不同的时期对等方获取不同的块的子集并且每个对等方拥有的子集不同,对等方还会访问临近对等方获取其块列表。然后该对等方就会采用一个最稀缺优先的技术,如果在临近对等方所拥有的所有块中某个块数量最少就优先转发这个块的副本,这样就能使得这个块迅速传播,其目的也是为了均衡每个块的分布和数量。

为了决定如何响应临近对等方的请求,BitTorrent也有一个对换算法,每隔一段时间对等方会测定他与每个临近对等方的通信速率,并按照速率给出优先权,优先向速率最高的4个邻居响应,每10s时间会更改响应的邻居,这就是疏通。而且每过30s对等方还需要随机选择另一位邻居发送块,如果双方通信速率足够高就继续进行数据的对换(双方将对方放入前四位的列表)直到发现了一个更好的通信对象。除了这前四个相邻对等方和一个试探的相邻对等方其余对等方都不能和对等方进行通信,也就是被阻塞。

2.6视频流和内容分发网

2.6.1因特网视频

在流式存储视频应用中,基础的媒体是预先录制好的视频,用户观看时向服务器请求视频。

首先来介绍视频,视频是图形以恒定速率播放,一张未被压缩、数字编码的图像是由像素阵列组成的,视频的一个很大的特征就是能被压缩,因而可以用bit率来衡量图像的质量。现今的压缩算法能将图像压缩成任意大小,比特率越高图像的质量也就越好。视频的越高突出特征就是高比特率,为了提供不间断的播放,网络必须为视频提供平均吞吐量,至少要和视频的比特率一样大。

2.6.2HTTP流和DASH

在HTTP流中,视频只是存储在HTTP服务器中作为普通的文件,每个文件都有一个特定的URL。当用户要看该视频时,客户与服务器直接建立TCP连接并发送对该URL的HTTP GET请求。服务器则以尽可能快的速率在响应报文中发送该视频文件。在客户一侧,字节被收集在客户的应用缓存里面,一旦缓存中的字节数量超过预先设定的门限,客户的应用程序就开始播放。特别是,流式视频需要周期性的从客户应用抓取帧,将帧解压并在用户屏幕上展示,因此流式视频应用接收到视频就进行播放并缓存后面的内容

HTTP流仍然有很大缺陷,就是尽管不同用户的带宽不同,但是接收到的视频编码是一样的,所以基于HTTP流又研发出了HTTP的动态适应性流(DASH)在DASH中,视频编码按照比特率分为了不同的版本,带宽更高时就使用质量更高的版本。这种特色对于移动用户十分重要,因为当移动用户移动时能清晰感受到带宽的波动。使用DASH后会在HTTP服务器存储不同版本的视频,每个版本都有一个不同的URL,在HTTP服务器中也有一个告示文件,为不同版本提供URL和比特率,而且DASH也允许客户在不同版本的视频之间进行切换。

2.6.3内容分发网

使用流式视频应用还有一些问题,一是客户如果远离数据中心,服务器到客户的路径会跨越多个ISP很容易影响分组的传输,第二是如果不同用户请求相同的文件公司也要为相同的文件多次为ISP支付流量的花费,第三就是数据中心是有限的,如果它发生故障就不能发送任何视频流了,这个区域的链路就会崩溃。

因此几乎所有的公司都会选择内容分发网(CDN),CDN负责管理分布在多个地理位置的服务器,并在服务器中存储视频(和其他文件)的副本,并且试图将所有用户请求定向到一个能提供更好服务的CDN位置。CDN可以是专用CDN,即为内容提供商自己所有,也可以是第三方的CDN,供多个内容提供商所有。

CDN一般有两个服务器安置原则,深入邀请做客

深入是指通过遍及全球的接入ISP中部署的服务器集群来深入到ISP的计入网中。目标是靠近端用户,减少用户和CDN集群之间的链路和路由器数量,改善用户体验。这种高度分布式的设计也带来了很多管理和维护等方面的挑战。

邀请做客是指通过少量的关键位置建造的大集群邀请ISP而不是把集群放在ISP里面,这个原则可能会以用户的高时延低吞吐量为代价产生低成本和管理维护开销。

1.CDN操作

当用户请求检索一个视频时(由URL标识)CDN截获客户请求,确定此时适合客户的CDN服务器集群,然后将客户请求重定向到CDN服务器。

CDN是如何截获客户请求的?大多数是采用DNS(前面讲过的域名系统)来截获客户请求,比如:一个内容提供商NetCinema雇佣了第三方CDN公司KingCDN向客户分享视频,当用户访问一个Web网页时,用户点击了一个连接http://video. netcinema.com/6Y7B23V,就是向对应的服务器video.netcinema.com发送了一个DNS请求。当本地DNS服务器(LDNS)将该DNS请求中转到NetCimema公司的一个权威DNS服务器上时,服务器识别到请求的主机名中的video,为了将该请求转交到KingCDN,该权威DNS服务器不会返回IP,而是返回一个KingCDN的域的主机名。然后请求就进入了第三方公司的专用CDN设施,用户就会发送第二个请求,即对第三方公司的主机名的DNS请求,第三方公司的DNS系统向LDNS返回对应的IP。然后LDNS向用户发送该IP,用户收到IP后建立连接发送HTTP GET请求,如果是DASH服务,服务器要先向用户发送URL告示文件,对应每个视频的不同版本,客户动态的选择不同的版本。

2.集群选择策略

任何的CDN部署,核心都是集群选择策略,即动态的将客户定向到CDN的某个服务器集群或数据中心。如上所述,经过客户的DNS解析,CDN得知了客户的LDNS服务器的IP地址,任何CDN需要基于这个IP选择一个合适的集群。

一个简单的策略是选择地理上最邻近的集群,但是这个策略忽略了可用带宽和时延随因特网路径时间的变化,总是为特定的用户选择特定的集群。另一种策略是实时测量时延,选择时延最短的集群,缺点是很多LDNS并不会响应来自集群的测量。

2.6.4学习案例

略,书上在此介绍了Netflix(美国的一个在线电影和TV节目服务提供商)和YouTube,具体内容可以到原书P100查看

2.7套接字编程

网络应用程序一般有两种,一种是在协议中定义好的应用程序,具有特定的通信方式;另一种就是协议里面没有定义过的,需要开发者自己设计开发的应用,这时候大多数会用到socket编程。具体的socket编程以及网络编程的内容我会在以后发布的TCP/IP网络编程栏里面讲述。

注:原书是用Python 3写的简单的TCP以及UDP程序,TCP/IP网络编程所使用的是C语言,不过具体的格式几近相同。

首先,网络应用是由两部分组成,即服务器程序和客户程序,当运行这两个程序时,这两个程序之间可以相互通信。开发者的任务也就是编写这两部分的代码。

网络应用程序有两类,一类是在应用层被协议、标准等定义好的,如根据HTTP、SMTP等实现的应用程序,这类程序的协议基本上是公开的,大部分基于此设计的程序都能相互进行交互;第二类是专用的网络应用程序,由开发者编写的网络协议没有被公开,基本上由开发者团队独立实现,所以其他开发者也难以开发出能与这类程序进行交互的程序。

本章中会使用Python 3写一个简单的网络应用。

2.7.1UDP网络编程

在应用层层面上,应用程序只能选择使用传输层的什么服务,但是基本上不能影响传输层内部的服务。

在编写使用UDP套接字的应用程序时,由于UDP的无连接特性,进行通信前需要先附带上对应的目的地址(IP+端口号),因特网会调用底层的服务进行数据的传输。目的地址,首先是标识目的主机地址的IP,其次为了定位到对应的进程,我们还需要一个能标识对应进程的字段,也就是端口号。在主机中每个进程都对应着多个套接字,这些套接字是传输层提供的一些接口,用于在应用层使用传输层的服务进行数据的传输。每个套接字也都对应着一个端口号,用于套接字的标识。所以网络编程中一个套接字的定位往往是通过主机IP+套接字端口号来标识的。而且UDP是无连接的,不仅意味着你要知道往哪里传输数据,还需要让接收方知道数据的来源也就是要附带源地址,这部分通常是由操作系统自动完成的,不需要在代码中表示出来。

接下来我们写的客户-服务器程序要实现以下功能:

1.客户端输入一串字符

2.服务器端把字符转为大写并返回给客户

3.客户显示返回的字符

代码如下,服务器程序是UDP_Server.py,客户程序是UDP_Client.py.

1.UDP_Client.py

'''
这一行是头文件 包含了所需要的库
'''
from socket import *

'''
这个是服务器主机名字,可以输入包含主机名的字符串,或者输入回环IP地址127.0.0.1或localhost(这是一个127.0.0.1的映射)
如果使用主机名,会对该主机名进行DNS解析获取对应的IP地址
第二行是个整数变量,将其赋值为12000,其实就是定义服务器使用端口12000
这里我使用的是回环地址
'''
serverName=('127.0.0.1')
serverPort=12000

'''
创建了客户的套接字,第一个参数是地址簇,AF_INET是指ipv4,AF_INET6是ipv6,通常是使用前者
第二个参数是套接字类型,SOCK_DGRAM表示这是UDP套接字
'''
clientSocket=socket(AF_INET,SOCK_DGRAM)

#这里是先输出‘’内的提示词,然后接收用户的输入并存储到字符串变量message中
message=input('Input lowercase sentence:')

'''
首先使用encode()方法把字符串转变为字节,因为套接字中要发送字节
然后方法sendto()为报文附上服务器进程的主机名和端口号,即(serverName,serverPort)并向clientsocket发送结果分组
如前所述,在这里操作系统自动的将源地址附带上去了
'''
clientSocket.sendto(message.encode(),(serverName,serverPort))

'''
当一个分组到达客户端套接字时,分组的数据被放到变量modifiedMessage中,源地址被放在serverAddress中
recevfrom(2048)表示缓存区可以接收最多长度为2048的字符
'''
modifiedMessage,serverAddress=clientSocket.recvfrom(2048)

#将报文转为字符串后输出
print(modifiedMessage.decode())

#关闭套接字与对应用户进程
clientSocket.close()

2.UDP_Server.py

from socket import *
serverPort=12000

#这里是创建一个服务器UDP套接字
serverSocket=socket(AF_INET,SOCK_DGRAM)

'''
bind()是用于绑定的方法将套接字与对应的端口号绑定,也就是为套接字分配端口号
'''
serverSocket.bind(('',serverPort))

#打印提示词
print("The server is ready to receive")

'''
一直循环执行最后三行代码
'''
while True:
    message,clientAddress=serverSocket.recvfrom(2048)

    #将报文转为字符串再转为大写(使用的是upper()方法)
    modifiedMessage=message.decode().upper()

    '''
    附带客户端进程的地址,将大写的字符串转为字节再发送给客户端进程
    '''
    serverSocket.sendto(modifiedMessage.encode(),clientAddress)

运行结果如上,绿色的是我的输入,白色的程序的输出,第一个是客户端进程,第二个是服务器端进程。可以看到程序的一切功能都正常,而且客户端接收到字符串后关闭了套接字,而服务器端进程的套接字一直处于打开状态。

2.7.2TCP套接字编程

与UDP不同TCP是面向连接的,意味着用户进程和客户端进程再发送数据前要先通过握手的机制建立连接,这时需要双方的地址。连接建立后只需把数据投入连接即可。

TCP连接建立过程通常是通过用户进程和服务器进程之间的三次握手实现的,具体实现流程如下:首先是用户进程请求与服务器进程建立连接,然后服务器进程同意建立连接并发送确认,最后用户进程确认连接已建立。这三次握手时信息传递时并没有建立连接,信息的传递其实是通过一个临时的套接字,也叫做欢迎套接字传输的,当连接建立时该套接字就会关闭,并打开新的连接套接字负责数据的交互。

1.TCP_Client.py

from socket import *
serverName='127.0.0.1'
serverPort=12000

#创建一个TCP套接字,SOCK_STREAM对应TCP
clientSocket=socket(AF_INET,SOCK_STREAM)

'''
connect()方法用于建立连接,传入服务器进程的地址
'''
clientSocket.connect((serverName,serverPort))
sentence=input('请输入文本:')

'''
使用send方法传输数据,传入的是sentence字符串并使用encode()方法转换为字节
'''
clientSocket.send(sentence.encode())
modifiedSentence=clientSocket.recv(1024)
print('用户发送了:',modifiedSentence.decode())
clientSocket.close()

2.TCP_Server.py

from socket import *
serverPort=12000

#这个是欢迎套接字
ServerSocket=socket(AF_INET,SOCK_STREAM)
ServerSocket.bind(('',serverPort))

#listen()方法是监听的意思,里面传入的参数代表服务器最多可以监听几个进程,也就是最多同时建立多少个连接
ServerSocket.listen(1)
print('用户正在发送信息:')

'''
因为TCP数据传输完以后需要断开连接,所以需要关闭连接套接字,再次连接时重新打开新的连接套接字
'''
while True:

    #这里打开的是连接套接字
    connectionSocket,addr=ServerSocket.accept()
    sentence=connectionSocket.recv(1024).decode()
    capitalizedSentence=sentence.upper()
    connectionSocket.send(capitalizedSentence.encode())

    #TCP与UDP不同在传输完信息后,虽然服务器进程不关闭,但是服务器与客户之间的连接需要断开
    connectionSocket.close()

具体的与UDP类似,不再赘述了。

2.8小结

本章中学习了网络编程的概念以及实现两方面,学习了客户-服务器系统模式,P2P系统模式并对这两种模式进行了对比。讲述了HTTP协议,SMTP协议,DNS协议以及一些相关应用和具体的流程。学习了流式视频以及现代视频分发系统是如何使用CDN的,以及对socket编程的基本语法的一些介绍(对TCP、UDP等socket编程的讲述也可以看以后的TCP/IP网络编程)对应用层有了一个基本的了解,下一章节需要讲述应用层之下的传输层,包括具体的TCP和UDP协议的内容和实现原理以及是如何进行工作的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值