自顶向下,那就先开始应用层。

梗概

网络应用是计算机网络存在的理由,如果我们没有网络应用的话,那计算机网络将毫无意义。

应用层是最好的学习起点。

应用层协议原理

因为网络的核心设备(路由器、交换机)不在应用层,因此我们编写网络程序不需要考虑网络层和链路层的一些事情,这样就提升了网络应用的开发效率。

网络应用程序体系结构

当今有两大应用程序体系结构:

  • 客户端/服务器结构(Client/Server)
  • 对等体系结构(P2P)

常见的,如 Web,Telnet,FTP,Mail 等都是 C/S 体系结构,我们把主动发起请求的端系统称为客户端,被动等待请求的端系统称为服务器,在这个体系结构当中,两个客户端是不直接通信的。比如仅仅使用浏览器,你无法直接建立一条连接。如果服务量比较大的话,一台主机显然不足以支撑服务的平稳运行。为此,配备大量主机的数据中心(data center)常被用于创建强大的虚拟服务器,相当于是在做负载均衡,把请求平摊到每一个主机上面。

而P2P的通信双方是对等方,相当于直接点对点通信,我只要知道你的ip地址我就可以直接对你发你起通信,如果我们都安装了同一个P2P的程序。比如飞鸽传书就是很典型的P2P的例子,在这个软件中,我们可以对其它主机发送数据,不需要连接额外的服务器。P2P体系结构的最引人入胜的特性之一是它们的自扩展性(self-scalability) o例如,在一个P2P文件共享应用中,尽管每个对等方都由于请求文件产生工作负载,但每个对等方通过向其他对等方分发文件也为系统增加服务能力,但是由于去中心化,它的安全性和可靠性需要衡量。

进程通信

其实在 CSAPP 这本书也有提到过,请求服务器的一个过程实际不是直接使用主机去通信,而是需要在服务端运行一个服务进程,用于接收请求,处理请求,返回结果,而且一个服务器不止能运行一个服务的特点也说明了这个问题。

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

客户和服务进程

就像前面说的:在一对进程之间的通信会话场景中,发起通信(即在该会话开始时发起与其他进程的联系)的进程被标识为客户,在会话开始时等待联系的进程是服务器。

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

在应用层一个称为套接字(socket)的软件接口向网络发送报文和从网络接收报文,套接字相当于是传输层的一个应用程序接口(Application Programming Interface,API)。我们在应用层编程,我们可以发送任何想发送的数据,但是我们不能控制传输层的收发等机制。我们最多可以选择我们发送的目标和发送所使用的传输层协议,又或者是其它的运输层参数。一旦应用程序开 发者选择了一个运输层协议(如果可供选择的话),则应用程序就建立在由该协议提供的 运输层服务之上。

进程寻址

这其实就是端口的一个作用了,一般来说,有 0-65535 标号的端口号。如果一个进程想尝试接收一个来自网络的请求,那么它必须绑定一个端口号,因为一个主机可以运行不止一个网络应用程序,因此如果包内只含有目的地址的话,可能会产生歧义,操作系统并不知道应该发送给哪一个进程,除此之外,相应的也需要让客户端发送的请求指向你所绑定的端口号,才能正常通信。

目前我们已经给流行的应用分配了特定的端口号。例如,Web服务器用端口号80来标识。邮件服务器进程(使用SMTP协议)用端口号25来标识。

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

一个网络应用程序应该如何选择传输层所使用协议呢,我们需要从以下四个方面来考虑:

可靠数据传输

如一些重要的信息,邮件,金融,文档传输等重要的应用,如果出错那么后果不堪设想,因此为了支持这些应用,必须做 一些工作以确保由应用程序的一端发送的数据正确、完全地交付给该应用程序的另一端。如果一个协议提供了这样的确保数据交付服务,就认为提供了可靠数据传输(reliable data transfer) 。

当一个运输层协议不提供可靠数据传输时,由发送进程发送的某些数据可能到达不了接收进程。这可能能被容忍丢失的应用(loss-tolerant application)所接受,比如多媒体的应用,看视频的时候少那么两帧基本不会出现干扰,允许一定的数据丢失。

吞吐量

网络吞吐量是指在没有帧丢失的情况下,设备能够接受的最大速率

首先明确一点是:吞吐量我们总是希望越大越好的,但是我们必须考虑有些时候,网络环境不是很好的情况下。具有吞吐量要求的应用程序 被称为带宽敏感的应用(bandwidth-sensitive application)

带宽敏感的应用具有特定的吞吐量要求,而弹性应用(elastic application)能够根据 当时可用的带宽或多或少地利用可供使用的吞吐量。电子邮件、文件传输以及Web传送都属于弹性应用。

定时

运输层协议也能提供定时保证,比如玩游戏时的延迟,较长的延迟就会使得游戏失去较强的体验感。

安全性

运输协议能够为应用程序提供一种或多种安全性服务,因为我们常用 TCP 协议只实现了可靠传输,并没有实现安全通信,数据包的内容被明文编码在包中,链路上的任何一台设备都可能会记录你所发送的包,造成信息泄露。

因特网提供的运输服务

那就是 TCP 和 UDP 了。

当你(作为一个软件开发者)为因特网创建一个新的应用时,首先要做出的决定是,选择UDP还是选择TCP。每个协议为调用它们的应用程序提供了不同的服务集合。

TCP服务

TCP服务模型包括面向连接服务可靠数据传输服务。当某个应用程序调用TCP作为其运输协议时,该应用程序就能获得来自TCP的这两种服务。

  • 面向连接的服务:在发送数据之前,会有一个握手阶段,提醒客户端和服务端,即将有大量的分组交换,这条连接是全双工的,在结束报文发送的时候,必须拆除该连接。
  • 可靠的数据传输服务:能无差错,按适当顺序交付所发送的所有数据,不会有字节丢失或者冗余。

TCP协议还具有拥塞控制机制,当发送方和接收方之间的网络出现拥塞时,TCP的拥塞控制机制会抑制发送进程。

UDP服务

UDP是一种不提供不必要服务的轻量级运输协议,它仅提供最小服务。UDP是无连接的,因此在两个进程通信前没有握手过程。UDP协议提供一种不可靠数据传送服务,也就是说,当进程将一个报文发送进UDP套接字时,UDP协议并不保证该报文将到达接收 进程。不仅如此,到达接收进程的报文也可能是乱序到达的。

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

今天的因特网通常能够为时间敏感应用提供满意的服务,但它不能提供任何定时带宽保证。

比如因特网电话,通常能容忍数据丢失,但是又带宽要求,因此 TCP 的拥塞控制机制就不适合因特网电话应用,这个应用通常更愿意使用 UDP 协议。但是因为有些防火墙阻挡 UDP 流量,因此如果 UDP 通信失败就会转而使用 TCP 协议作为备份。

应用层协议

应用层协议定义了:

  • 交换的报文类型,例如请求报文和响应报文。
  • 各种报文类型的语法,如报文中的各个字段及这些字段是如何描述的。
  • 字段的语义,即这些字段中的信息的含义。
  • 确定一个进程何时以及如何发送报文,对报文进行响应的规则。

有些应用层协议在 RFC 文档中定义,因此他们是公开的。Web的应用层协议HTTP (超文本传输协议)就作为一个RFC可供使用。还有很多别的应用层协议是专用的,有意不为公共域使用,比如 QQ 的 OICQ 协议。

区分网络应用和应用层协议是很重要的,应用层协议只是网络应用的一部分,比如说电子邮件的首要应用层协议SMTP也只是电子邮件应用的一个部分。

Web 和 HTTP

到了 20世纪90年代初期,一个主要的新型应用即万维网(World Wide Web)登上了舞台,Web是一个引起公众注意的因特网应用,它极大地改变了人们与工作环境内外交流的方式。它最大的特点是按需操作,而不是像广播和电视那样,用户只能被迫收听内容提供者所提供的节目。

web 作为一个应用平台,同时也为某些视频提供网站(YOUTUBE)和电子邮箱(GMAIL)提供了极大的方便。

HTTP概况

Web的应用层协议是超文本传输协议(Hyper Text Transfer Protocol,HTTP)。

回顾一下WEB的一些概念:

Web页面(Web page)(也叫文档)是由对象组成的。一个对象(object)只是一个文件,诸如一个HTML文件、一个JPEG图形、一个Java小程序或一个视频片段这样的文件, 且它们可通过一个URL地址寻址。

HTTP是基于TCP协议的无状态的协议,也就是说,在不同的地方,请求完全一样的情况下,如果 WEB 程序没有对 IP 来源做任何检查,得到的结果应该是一致的(在不涉及修改服务器文件或数据库的请求中),并且假如某个特定的客户在短短的几秒内两次请求同一个对象,服务器并不会因为刚刚为该客户提供了该对象就不再做出反应,而是重新发送该对象。

HTTP 协议也不担心从网络的数据丢失和乱序故障中恢复的细节。那是TCP以及协议栈较低层协议的工作。

非持续连接和持续连接

其实很简单,就是每次请求都使用单独的 TCP 来连接的就是非持续连接,采用相同的 TCP 连接就是持续连接。

非持续连接

这里有一个时间概念,从发出请求到我们完全接收完请求所使用的时间为 RTT,对于一个非持续连接的 web 服务,我们每次请求都需要两倍的 RTT,因为 TCP 的三次握手中,前两次会消耗一个 RTT,第三次的时候发送请求到接收请求又消耗一个 RTT。

持续连接

非持续连接的主要缺点就是每次请求都需要维护 TCP 连接,耗时两倍 RTT,因此就有了持续连接的方式。

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

HTTP报文格式

大体上,HTTP的报文分为两个类型:

  • HTTP请求报文
  • HTTP响应报文

请求报文

一个典型的报文分为三个部分:

  • 请求行
  • 请求头
  • 请求实体

先放一个 HTTP 报文的格式:

来看看一个经典的 HTTP 请求。

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

首先很明显可以发现,HTTP 请求是以 ASCII 码为主的。

请求报文的第一行就叫请求行(request line),里面携带了三个信息:请求方式,请求路径,协议版本。

请求方式包括GET、POST、HEAD、PUT和DELETE。绝大部分的HTTP请求报文使用 GET 方法。

请求路径为 /somedir/page.html

HTTP 协议的版本号为 HTTP/1.1

之后的每一行都可以理解为请求头(header line),直到一个空行结束。

在上面那个例子中,请求头是采用键值对的形式组成的。

Connection: close 是告诉服务器,请求完成之后就关闭连接。

User-agent: 请求头用来指明用户代理,即浏览器的类型。

Accept-language: 请求头表示我浏览器所支持的语言类型。

Host: 请求头指明了我要访问的主机。

响应报文

其实差不多,只不过请求的时候叫请求行,响应的时候这一行叫状态行

状态行有3个字段:协议版本字段、状态码和相应状态信息。

同样看一个例子

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: Tuer 18 Aug 2015 15:11:03 GMT
Content-Length 6821
Content-Type text/html
(data data data data data ...)

在这里可以看到服务端响应我们,协议版本是 HTTP/1.1,状态码为 200,本次请求 OK,没有啥问题。

状态码及其相应的短语指示了请求的结果。一些常见的状态码和相关的短语包括:

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

如果想体验真实的 HTTP 报文,可以使用 Telnet 登录到 web 服务器,然后按照一定要求发送请求包便可得到真实回应,这个之前在 CSAPP 的时候做过了,应该在网络编程那一章,这里不西索了。

用户与服务器的交互:cookie

我们请求的时候,有一个请求头可以是 cookie 字段,该字段标识了服务端给我的一个 cookie 信息,此次我请求带上了这个 cookie 信息,cookie是由浏览器自动保存的。

当我们请求一个服务器的时候,如果服务器开启了 cookie 认证,那么在第一次请求的时候大概率响应头中会包含 Set-cookie 字段,这里会告诉我们服务器给了我们什么样的身份,这个身份什么时候过期,一般来说,浏览器在 cookie 过期后会自动删除。

cookie的出现给无状态的HTTP协议加上了一个状态,这个状态就相当于是我们的身份证。好比我们去淘宝网页购物,我点击了购买之后,服务器肯定需要知道是谁购买的。无状态的劣势就产生了,因为在请求一样情况下,不同的人得到的同一个web服务器的结果是一模一样的,这肯定不行。因此有了 cookie 服务器就知道是谁请求的了,书上的例子并不太适合当前的环境,因为如果用户是数字这样的简单编码,就会导致我请求的时候虚假构造 cookie 获取其它用户对应的访问权限。

因此 cookie 身份认证机制中的 cookie 不宜过于简单,也不应该携带任何敏感信息,在设置了cookie 之后,服务器也会存一份在后台的数据库当中,以便于在处理请求的时候查找数据库得到用户的身份。

WEB缓存器

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

其实就跟代理一样,在请求实际服务器之前先请求了一个中间人,中间人代替我们请求真实的服务器,完成之后把响应的返回包给了我们,但是有一点不同的是它的作用是存储 web 对象所使用的,用于分担真实服务器的压力。如果说真实的web服务器没有更新过那个对象,那么就直接把本地存储的对象以 HTTP 报文的形式返回给客户端。

这里举了一个实际的例子来证明这个 WEB 缓存器的好处。

我们可以看到,客户端和服务端之间用一个 15Mbps 的链路连接起来了。假设请求包可以小到忽略不计,只考虑相应包,再假设每个相应包大小都是 1Mb,那么每秒 15 个请求足以把整个接入链路占满,并且此时流量强度为 1。前面说过,流量强度为1的时候,排队时延为无穷大。

那么为了解决这个问题,不让这 15 Mbps 的速率限制 100 Mbps 的速率,我们有两个方案:

  • 增加接入链路带宽,显然,这是一种代价非常高的方案。
  • 第二种情况就是在机构网络中安装一个Web缓存器,如图所示

假设缓存命中率为 0.4,那么此时 15 个请求中只有 60%的请求去请求了初始服务器,经过了接入链路。除此之外其成本较低,很多缓存器使用了运行在廉价PC上的公共域软件。

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

条件GET方法

其实很简单,就是在请求的时候包含一个 If-Modified-Since: 的请求头,这个请求头告诉了服务器我本地存储的了什么时间获得的对象,此时服务器判断在这个时间点之后,服务器的对象有无被更改,如果被更改,那么发送新的内容给客户端,否则发送 304 状态码告诉客户端 Not Modified 并且实体行为空,大大节省了带宽,本地存储的对象是服务器最新的对象。

因特网中的电子邮件

来看一个邮件系统的工作图

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

SMTP

这么去理解:

首先看邮箱格式: username@host@ 分隔的用户名和主机地址。

每个人要使用某个主机的邮件服务必须申请邮件服务的一个用户名。假如 Alice 申请了 Alice@a.com 的邮箱,Bob 申请了 Bob@b.com 的邮箱。Alice 发送 Bob 信息是这样的过程:

  • Alice 通过用户代理,把自己写好的文章,通过 SMTP 协议投递到自己的邮箱所在的服务器。
  • 服务器发现队列中有一封邮件,开始处理,发现这是一封发送到 Bob@b.com 的邮件,于是与主机 b.com 建立一条 TCP 链接。
  • a.com 的邮件服务器通过 SMTP 协议在 TCP 链接上面发送 Alice 的报文。
  • b.com 的邮件服务通过 SMTP 接收该邮件,把它归类为 Bob 收到的邮件。
  • 在 Bob 登录邮箱的时候,认证身份完毕之后会自动请求 b.com 的邮件服务器,下载所有属于 Bob 的邮件。

总结下来是这样的一个过程:

邮件服务器之间一般不会有代理,即使服务器相隔很远,它们也是直接建立 TCP 链接,特别的,如果发送的服务器被关闭,则 a.com 会对此封邮件进行保留,直到 b.com 重新开启再重新建立新的 TCP 链接去发送邮件。

在 TCP 握手之后,服务器会开始介绍自己,发送的服务器会介绍发送者是谁,接收者又是谁,之后会发送报文,SMTP能够依赖 TCP 进行无差错的投递信息。

自己去试了一下 SMTP 协议,感觉就跟一个SHELL一样,挺好玩的,根书上说的一样,还是要自己试一试才能真的去理解这个 SMTP 协议。

之前还在想呢,如果我叫什么我自己都可以决定,那么伪造邮件服务器(比如我说我叫qq.com)岂不是很容易,后来细细想想发现其实也就是跟 DNS 差不多,你最多可以让自己一部分的人信你自己是 qq.com,而其他人压根不认,qq.com 这个域名被腾讯注册了,腾讯把它解析到哪就归腾讯管了,跟你没关系。而外面的人想要发送邮件给 qq.com 的邮箱,人家直接找域名服务器,怎么都发不到你这的,所以你就像个小丑哈哈哈。

SMTP与HTTP的对比

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

还有就是,SMTP 的报文只接受 7 比特的ASCII码数据,HTTP没有这种限制。

最后一个区别就是 HTTP 对于每个对象来说,都会单独的使用一个请求来获取,而SMTP把所有对象放在一个报文当中。

邮件报文格式

一个邮件的基本信息是这样的:

1
2
3
From: sender@example.com
To: recv@example.cn
Subject: test

正文输入需要我们使用 data 命令,我们会以一行单独的一个 . 来表示数据的结束,这样就发送完了整个完整的邮件报文。

邮件访问协议

邮件访问协议服务有两种模式,一种是下载并删除,另一种是下载并保存,就是字面意思,前者的缺点很明显,就是当我在PC端接收到邮件之后,我不能再从其它客户端接收到邮件,而后者很明显的缺点就是会增加服务器的负载。

POP3

邮件访问协议一般是使用 POP3,默认端口 110,我们同样可以使用 telnet 去测试。

可以用以下格式做鉴权

1
2
3
4
5
6
telnet mailserver 110
+0K POP3 server ready
user bob
+0K
pass hungry
+0K user successfully logged on

登录成功之后便可以取得属于自己邮箱的邮件信息了,登录之后可以使用这些命令 list,retr,dele 来列出,下载,删除邮件。一般来说,POP3选择的是下载并删除。

IMAP

基于POP3的这种问题,就出现了 IMAP 协议。

IMAP服务器把每个报文与一个文件夹联系起来;当报文第一次到达服务器时,它与收件人的 INBOX 文件夹相关联。收件人则能够把邮件移到一个新的、用户创建的文件夹中,阅读邮件,删除邮件等。IMAP 协议为用户提供了创建文件夹以及将邮件从一个文件夹移动到另一个文件夹的命令。IMAP 还为用户提供了在远程文件夹中查询邮件的命令,按指定条件去查询匹配的邮件。值得注意的是,与 POP3 不同,IMAP 服务器 维护了 IMAP 会话的用户状态信息,例如,文件夹的名字以及哪些报文与哪些文件夹相关联。

还有一个重要特性就是支持按需获取邮件,比如在接收邮件的时候,我不会希望接收的时候把所有附件下载下来,这样对于用户而言不太友好,而 IMAP 协议就支持按需获取附件。

基于Web的电子邮件

web 的出现让我们的邮件客户端有了新的载体。web 的出现使得我们用户层面只使用 HTTP 便可以完成邮件的收发。

DNS:因特网的目录服务

对于一个主机来说,我们更乐意记住它叫什么而不是它的编号是什么,跟学校里老师叫学生一样,我们也仅仅比较乐意记住你的名字而不是记住你的学号,DNS的出现就是解决这个问题的。

在因特网中,同样也存在着这个问题,对于主机名,人们更愿意域名,而不是 IP 地址。

DNS提供的服务

对于人来说,更喜欢域名的记忆方式,但是对于路由器来说,它喜欢定长的有着层次结构的IP地址。为了满足不同的需求,我们需要一种能进行主机名到IP地址转换的目录服务。这就是域名系统 (Domain Name System,DNS)的主要任务。

DNS是:

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

DNS协议运行在UDP之上,使用 53 号端口。

DNS 通常为其它协议服务,我们并不直接使用。比如我们在输入一个网址访问的时候,如果网址是一个域名,则会先进性一次 DNS 查询。DNS 服务器会返回给我们域名所对应的 IP 地址,于是客户端马上和对应 IP 地址的主机建立 TCP 连接。

这看起来带来了额外的时延,实际上我们根本感受不到,因为我们要查询的域名通常会在附近 DNS 的缓存中。

主机别名

一个公司的真正的邮件服务器可能并不是简单的 qq.com 而是 mail.qq.com 的一个主机,但是我们更愿意记住 qq.com 而不是要多记一个子域。这里我们把 qq.com 别名(host aliasing),mail.qq.com 称为规范主机名(canonical hostname)

主机规范名

事实上,邮件应用程序可以调用 DNS 获取主机规范名和 IP 地址,这样我们就不必记住主机规范名了。

DNS工作机理概述

在 UNIX 的主机上,可以通过使用 gethostbyname 函数发起 DNS 请求得到域名对应的 IP 地址。

DNS介绍

DNS 是一个分布式、层次数据库。

在这里,根 DNS 服务器指示了顶级域(Top Level Domain,TLD)的 DNS 服务器 IP 地址,而顶级域 DNS 服务器指示了它们下面的二级域的 IP 地址。

权威 DNS 服务器指的是一个机构组织所指定的 DNS 服务器,因为通常来说,在该 DNS 解析的域名都属于该公司的子域,这些解析的结构一定也是属于这个公司的。

还有另一类重要的DNS服务器,称为本地DNS服务器(local DNS server),这个DNS服务器不在层次结构当中,是由 ISP 提供的,比如我用移动的网络,移动给我提供了一个 114.114.114.114 域名服务器作为自己的本地域名服务器,那么查询的过程是这样的:

上面的查询方式是迭代查询,还有一种是递归查询:

DNS缓存

就是在本地或者是中间的一些 DNS 服务器中,会保留部分解析的记录,如果再次被遇到那么就不会再走那么多流程了,而是直接把缓存结果发送给你。

DNS记录和报文

DNS记录

实现 DNS 分布式数据库的所有 DNS 服务器存储了资源记录(Resource Record,RR), RR提供了主机名到IP地址的映射。

资源记录是一个包含了下列字段的4元组:

(Name,Value,Type,TTL)

TTL是该记录的生存时间,它决定了资源记录应当从缓存中删除的时间。

Name和Value的值取决于Type:

  • 如果Type = A,则Name是主机名,Value是该主机名对应的IP地址。因此,一条 类型为A的资源记录提供了标准的主机名到IP地址的映射。
  • 如果Type = NS,则 Name 是个域(如foo. com),而Value是个知道如何获得该域中主机IP地址的权威 DNS 服务器的主机名。例如 (foo.com,dns.foo.com,NS) 就是一条类型为NS的记录。
  • 如果 Type=CNAME,则 Value 是别名为Name的主机对应的规范主机名,该记录能够向査询的主机提供一个主机名对应的规范主机名,比如 (xia0ji233.github.io,xia0ji233.pro,CNAME)。这让我想起来了,我这个 github 的blog解析域名的时候,就直接创建一个 CNAME 文件,然后写上我的那个域名,这样再次输入 xia0ji233.github.io 会自动跳转到 xia0ji233.pro。最常见的还有 (qq.com,www.qq.com,CNAME)
  • 如果Type = MX,则 Value 是个别名为 Name 的邮件服务器的规范主机名。比如 (qq.com,mail.qq.com,MX)

可能会奇怪,就是 NS 记录中为什么得到的还是一个域名,那其实是,在顶级域服务器当中,dns.foo.com 的一条 A 类型的记录也在其中。

DNS报文

大概长这样

这个大概看看吧,知道有这么几个关键标志位就行了。

在DNS数据库中插入记录

需要想域名服务商申请注册,一般会添加一条主域名信息和 DNS 服务器的信息,也就是一条 NS 类型记录和一条 A 类型记录。

P2P文件分发

也不知道为啥,不太想看,可能是因为这一章平时应用场景过少了。

视频流和内容分发网

因特网视频

一般的视频网站采取的都是流式视频,用户并不需要事先下载完整个视频,而是可以边下载边看,按需下载。

对流式视频的最为重要的性能度量是平均端到端吞吐量。为了提供连续不断的布局,网络必须为流式应用提供平均吞吐量,这个流式应用至少与压缩视频的比特率一样大。

HTTP 流和 DASH

其实就是可以基于用户的带宽自适应地流 DASH,在我们看来就是可以选择清晰度和流畅度嘛。

内容分发网(CDN)

主要是怕单点故障导致对所有人停止服务。几乎所有主要的视频流公司都利用内容分发网(Content Distribution Network, CDN)。它分为:

  • 专用CDN (private CDN),即它由内容提供商自己所拥有
  • 第三方CDN (third- party CDN),它代表多个内容提供商分发内容

CDN通常采用两种不同的服务器安置原则:

  • 深入:深入到 ISP 接入网中,以此来靠近端用户从而改善用户感受的时延和吞吐量,但是因为过于分布,管理起来非常麻烦。
  • 邀请做客:通过在少量关键位置见到大集群来邀请ISP做客。不是将集群放在接入ISP中,这些CDN通常将他们的进群安置在因特网交换点(IXP)。这种方式通常维护和管理的开销比较小,但是可能会有较高的时延。这一种理解为与第一种方法相对就好了。

CDN操作

大多数CDN利用DNS来截获和重定向请求。

当我访问内容提供者时,发生了以下事件:

  • 客户端请求内容提供者(NetCinema.com)的网页。
  • 主机发出 DNS 请求到本地 DNS 服务器上,这里略掉解析出 NetCinema 权威 DNS 服务器的过程。
  • 此时权威 DNS 服务器没有返回直接到该网页的 ip 地址,而是返回了 cdn 提供者的权威 DNS 服务器地址。
  • CDN 权威 DNS 服务器解析出最近的一个 CDN 主机,回传到本地 DNS 服务器上。
  • 本地 DNS 服务器完成解析,解析到了 CDN 服务器上。
  • CDN 服务器返回结果。

对于内容提供者来说,我只需要修改自己的权威 DNS 服务器到 CDN 上即可。

集群选择策略

CDN 主要起到分流和加速的作用。对于加速而言,集群的选择策略也比较重要。

  • 一种简单的策略是指派客户到地理上最为邻近(geographically closest)的集群。
  • 另一种测策略是基于当前流量条件为客户决定最好的集群。

学习案例:Netflix、YouTube 和 看看

大概就是讲了以下这些内容提供者所使用的cdn。

套接字编程

套接字是一个网络接口

TCP套接字

服务端:

1
2
3
4
5
6
7
8
9
10
11
12
13
from socket import *
serverPort = 12000
serverSocket = socket (AF_INET, SOCK_STREAM)
serverSocket. bind (('', serverPort))
serverSocket. listen (1)
print(' The server is ready to receive')
while True:
connectionSocket,addr = serverSocket.accept()
sentence = connectionSocket.recv(5).decode()
capitalizedSentence = sentence.upper()
connectionSocket.send (capitalizedSentence.encode ())
connectionSocket.close ()

客户端:

1
2
3
4
5
6
7
8
9
from socket import *
serverName = '127.0.0.1'
serverPort = 12000
clientSocket = socket(AF_INET,SOCK_STREAM)
clientSocket.connect((serverName, serverPort))
sentence = input('Input lowercase sentence ')
clientSocket.send(sentence.encode())
modifiedSentence = clientSocket.recv(5)
print('From Server 9 9 modifiedSentence.decode()) die nt Socket. close ()')

UDP套接字

好像区别就是,这里用了 sendtorecvfrom 两个接口去发送数据和接收数据,并且在创建socket的类型时,变成了 SOCK_DGRAM

小结

学到了挺多的,HTTP,SMTP,POP3,DNS协议,CDN等等的网络概念以及协议实现的细节,就是这花的时间久了点,希望后面章节能赶上来。