我们知道现代常用的计算机网络模型为5层模型,其中应用层是直接与我们平时常见的软件对接的最高层,所以先来学习应用层就显得很有必要了。其中在应用层我们需要学习网络应用程序的实现、原理并且了解网络应用程序所需要的网络服务、客户和服务器、进程和运输层接口。
目录
一、应用层程序原理
1.1 应用程序体系结构
1.2 进程通信
1.2.1 客户和服务器
1.2.2 进程与计算机网络网络的接口
1.2.3 进程寻址
1.3 运输层协议选取
1.TCP协议
2.UDP协议
1.4 应用层协议
二、Web
2.1 Web页面
2.2 HTTP协议简介
2.3 HTTP报文格式
2.3.1 HTTP请求报文
2.3.2 HTTP响应报文
2.3.4 Web缓存
三、DNS
3.1 DNS的定义和原理
3.2 DNS记录和报文
3.2.1 DNS记录
3.2.2 DNS报文
四、电子邮件
4.1 电子邮件系统
4.2 SMTP
4.3 邮件报文格式与访问协议
4.3.1 邮件报文格式
4.3.2 邮件访问协议
五、P2P
5.1 BitTorrent
六、CDN
在应用层编写程序,一个重要的原则是要使编写的程序可以在不同的端系统运行,并且可以通过通信系统来进行传播。例如当用户访问某个网页时,我们电脑上的程序向Web服务器上的程序发送请求,这时候就实现了不同程序之间的简单通信;还有一种就是利用P2P共享文件实现不同端系统在相似的程序间的传输。
应用程序是不同于网络结构的存在,我们设计一个应用程序也要为该应用程序设计一个应用程序体系结构,它将决定如何在端系统中组织起这个应用程序。现代常见的应用程序体系结构有:客户-服务器体系结构和对等(P2P)体系结构。
客户-服务器体系结构:在这个体系结构中,总会有一台主机作为服务器向其它主机提供服务,该应用体系结构的特点很明确:1、客户机之间不互相通信。2、服务器的IP地址固定。其中著名的应用就是Web应用,我们的浏览器不能向其它用户的浏览器请求服务,我们只向Web服务器发送请求。但是使用这种体系常常会因为一个服务器已经不足以为越来越多的主机请求服务,所以需要建设一些配备主机的数据中心作为虚拟服务器。
P2P体系结构:P2P体系结构的特点是应用程序可以在主机对之间互相通信,这些主机对被称为对等方,并且这些主机对是客户所拥有,而不是服务器提供商。我们常见的使用P2P体系结构的应用程序有:比特精灵、迅雷等。P2P体系的一个重要特点是它具有很强的扩展性,因为在对等方之间可以互相传输可以增加系统的服务能力。
我们之前说的在应用层中是应用程序之间进行通信,但实际上是进程进行通信的,一个进程可以被理解为是运行在计算机上的一个程序。不同的端系统上的进程交换报文,发送报文,响应报文等动作构成了进程间的通信。
以两个进程间的通信为例,以发起通信的进程称为客户,而会话开始的时候等待联系的进程称为服务器。例如Web应用程序中,我们的浏览器进程就是客户,而Web的进程就是服务器。但是进程在P2P体系结构中,某个特定的端系统中的进程,它可以上传文件,也可以下载文件,所以一个进程是可以出现既作为客户,也作为服务器的情况的。
我们知道,进程之间只是应用层上的概念,而我们要想实现端到端的数据运输,需要经历下面层层次的运输,而在应用层和运输层之间的软件接口被称为:套接字(socket)。从另一方面来看,该接口实现了网络和应用的连接,所以也为网络应用编程提供了可编程接口,所以套接字也可以被称为应用程序编程接口(Application Programming Interface, API)。我们可以通过利用接口来控制应用层,也可以通过API控制少量运输层的功能。
如果我们有一个分组,我们应该如何将其发送给我们的目标主机呢?最实际的就是需要让我们的分组能够找到它,那么就需要用到寻址的功能。我们传输一个分组需要用到两个地址:主机的IP地址和进程的端口号。IP地址让数据能够找到这个计算机,而端口号让数据能够精准找到进程。一般来说进程都是有固定的端口号,例如Web服务器就是端口号80。
应用层的数据传输给运输层后,我们还要有选择性地对运输层的协议进行设置,我们常见的运输层协议是TCP和UDP协议,每一个协议都会调用相应的服务来为应用层服务。
TCP协议提供的的服务包括两个方面:面向连接服务和可靠的数据传输服务。
面向连接服务指的是采用TCP协议时两个端系统在发送信息前会进行一次控制信息的传输,提醒目的端系统做好接收数据准备,这个过程也被称为握手的过程,之后就可以建立起TCP连接来为接下来数据传输使用。
可靠的数据传输服务指的是我们采用TCP协议时发送的数据包能够无缺、无逆序、无差错地传输给我们的目的端系统。
与TCP协议相对应地,有一个UDP协议。该协议没有提供可靠的数据服务和面向连接的服务,也就是说它的数据可能出现丢失等许多问题,并且它也没有TCP的拥堵机制(也就是在数据包传输过程中拥堵时会进行先抑制发送方发送数据,等传输路径通畅了才让传输方发送数据,这样虽然消耗了实时性,但增强了可靠性,减少丢包现象)。同时也因为此UDP协议向下层的传输速率就不受控制了。
常见应用的协议选取:
既然是应用层的主题,当然不可避免要介绍应用层的协议。数据包由源主机上的进程发送,那么我们就需要决定发送发送数据包的各项规定,应用层协议就负责协调各个端系统上的进程如何合适地发送报文,它规定了:报文字段的语义、报文发送时间和方式等、报文类型(接收、发送)和报文各种报文类型的语法。应用层协议可以由RFC文档定义也可以自己私有定义。如果某个应用层协议可以作为RFC,那么使用该应用层协议开发的浏览器可以访问同样遵循该标准的服务器。
但是我们同时也要注意,某个应用层协议只是一个应用程序的组成部分,以Web应用为例,它的组成包括:Web服务器、Web浏览器、文档格式标准(HTML)和应用层协议。
前面是应用层的整体体系,下面先来仔细了解一下我们平时接触最多的Web应用程序和HTTP协议。
在学习HTTP协议之前,首先需要学习一个Web页面的组成。
一个Web页面是由一系列的对象组成,一个对象就是一个文件,这些对象可以是JPEG图片、JPG图片或者HTML文件等。而在这其中一般有一个HTML基本文件来对这些对象进行结构规划、架构搭建。所以正常情况下一个Web页面包括一个基本的HTML文件以及一系列对象组成,而HTML文件通过一个URL地址来找到这些对象(寻址)。下面是一个URL例子:http://www. someSchool. edu/someDepartment/pic.jpg,其中http://www. someSchool. edu是存储这些对象的主机名,而
超文本传输协议(HyperText Transfer Protocol, HTTP),是Web应用中最核心的应用层协议。我们平常的使用HTTP的通信是由客户端上的程序和服务器端的程序互相交换HTTP格式的报文来进行对话。其中Web的浏览器(IE、火狐、360等)就是客户端,Web的服务器(Apache和Microsoft Internet Information Server)就是服务器端。
而采用HTTP的应用通信根据其TCP连接的传输方式可以分为持续连接和非持续连接。持续连接是每个请求/响应都是通过一个单独的TCP连接传输,而非持续连接是不同的请求/响应是通过多个TCP连接传输。而我们生活中常用的是非持续连接,因为这样可以并行传输,将极大减少传输时间。
采用HTTP传输的报文分为两种:传输报文和响应报文;传输报文是客户端发送到主机端的报文,响应报文是主机端回馈给客户端的报文。
首先来看的是HTTP的请求报文,HTTP请求报文的格式以及书上的例子如下,这里的sp、cr、lf分别表示空格、回车和换行:
HTTP报文的第一行是请求行,它由三部分字段组成:方法、URL和版本。
方法有以下几种:GET、POST、HEAD、DELETE和PUT。我们平常的报文绝大多数用GET方法:发送请求,得到对象;HEAD是发送请求,得到回复但无所请求的对象,就只有回答没有内容;DELETE是删除服务器内的对象;PUT是上传对象到指定服务器的目录;POST是向服务器提交数据表单。
这里第二部分的URL是我们请求的对象的路径;而第三个的HTTP版本是自解释的,例子就是HTTP/1.1版本。
HTTP报文的第二部分是首部行,它用于确定报文的属性。例子中的HTTP报文的首部行还包括1、申请的服务器主机名,虽然我们已经建立TCP连接,但还是需要指定主机名。2、Connention:close--发送完成断开连接。3、User-agent--申请服务的浏览器类型。4、申请的语言类型。
注意到报文的末尾还有一段称为实体体的内容,这段内容是在我们使用POST方法时才使用,例如我们搜索某个东西,在搜索引擎输入某个搜索值。那么我们就需要使用POST方法并且在实体体中夹杂我们的输入表单信息。当然,某些情况下我们也可以不使用POST方法。例如HTML就使用GET方法,只不过它将输入的搜索值夹杂在要请求的URL中,例如我们输入字符c和d,那么请求的URL路径结构是/xxxxx/xxxxx/x.html?c&d。
HTTP的请求报文之后就是关于HTTP的响应报文:
HTTP的响应报文对应也有三部分:状态行、首部行和实体体。
状态行包括三个部分:协议版本、状态码和响应状态信息。响应报文例子中的协议版本就对应请求报文例子中的HTTP协议版本HTTP/1.1;后续就是200 OK状态码和状态响应信息,其它还有例如404 Not Found(服务器未找到请求资源)和403 Forbidden(拒绝访问)也属于HTTP状态码和响应信息。
而在首部行部分,响应报文也与请求报文类似。上面例子为例:Connection:close表示传输结束立即断开链接;Data表示请求日期;Server表示服务器名;Last-Modified表示最后一次修改日期;Content-Length表示内容字节数;Content-Type表示请求的对象是什么对象,而在最后就是包含实体报文的实体体。
cookie是一项技术,因为HTTP协议下服务器不存储用户信息,为了满足追踪用户信息的目的,cookie被开发出来。它由4个组件组成:响应报文的cookie首部、请求报文的cookie首部、客户端由浏览器管理的cookie文件和服务器数据库。
cookie技术实现原理:当我们第一次访问某个服务器A的网站B时,客户端回向服务器A发送一个请求报文,服务器A会生成一个特定的识别码并且在服务器后台数据库产生出一个表。最后服务器会发送一个包含set-cookie:首部的响应报文。我们浏览器会读取该报文并且将set-cookie:首部里面的识别码和服务器主机名记录进我们浏览器的cookie文件中。这样我们下次访问该网站就会在请求报文上添加该识别码,这样网站就能通过识别码等实现追踪、自动登录、记录用户信息等目的。
Web缓存器是一个拥有实体的代理服务器,它有自己的磁盘存储空间。它连接在我们的主机和服务器之间,可以存储我们近期请求的对象副本。有Web缓存器和无Web缓存器的网络请求过程如下:
有Web缓存器:客户端发送请求报文-->Web缓存器查找有无此副本
-->有,就将此副本发送回去
-->无,向对应服务器发送请求,获取该对象,存储在Web缓存器中并向浏览器发送副本
无Web缓存器:客户端发送请求报文------->服务器返回响应报文
可以看出Web缓存器新增了中间存储的功能,它可以大大缩短客户请求的响应时间:如果我们请求直接在Web缓存器上就直接响应。同时它还可以减少机构、公司接入链路接入因特网的通信量。通过接入Web缓存器将N台接入因特网的主机变成Web缓存器接入因特网,可以降低费用。
条件GET方法
我们知道如果浏览器请求的内容就在Web缓存器上是可以直接响应的。但是Web服务器上的对象是会发生更新的,所以检查Web缓存器上的对象的时效性就很有必要,为此引入了条件GET方法。这种方法其实是在使用GET报文的同时在首部行增加“If-Modified-Since”的内容。
它的具体实现如下:假如客户端向Web缓存器请求一个未请求过的对象,Web缓存器会向相应服务器发送请求报文,获得服务器的响应报文后将对象缓存的同时也会存下对象最后的修改日期。当客户端再一次向该缓存器请求时,缓存器会发送一个含有条件GET的报文给服务器,这个报文包含之前Web缓存器缓存下的最后修改日期,服务器得到请求报文后会比对服务器端的相应对象的最后修改日期是否发生了改变,如果发生了改变就发送新的对象回去,反之则发送一个不含实体内容的响应报文,这个相应报文状态行为304 Not Modified来告诉缓存器未发生改变。
DNS(Domain Name System)域名系统,是一个由分层的DNS服务器组合而来的分布式数据库,并能够让主机查询分布式数据库的应用层协议。它的功能是能够让主机名转换为IP地址的协议,主要提供一种从主机名到IP地址的转换服务,当然,它也可以进行1、主机/邮件服务器的别名服务(通过别名来找到主机的名字和IP);2、负载分配服务(用户申请时发送过去一个IP集合,并且循环次序,保证可以合理分配服务器负载)。它使用到的是UDP传输层协议并且使用53号端口(ps:如果我们想查看端口号,可以首先打开DOS窗口,输入netstat -an指令,本地地址列IP冒号后面的数字就是端口号。)。它的并不直接展示给用户,而是作为某项功能为软件提供服务。
接下来我们重新认识一下某个报文的传输过程:首先是一台拥有DNS客户端的主机,通过浏览器访问某个网址:www.baidu.com,那么我们浏览器会从URL中抽取出主机的名字:www.baidu.com给DNS客户端,客户端拿到后会发送给DNS服务器,DNS服务器会返回一个响应报文里面包含百度服务器的IP地址,然后我们浏览器才会和百度的服务器建立TCP连接进行通信。
而DNS作为一个连接全球许多主机的系统,必然需要进行分布式的结构将其服务器分散到各地。常见DNS服务器分为三个种类:根DNS服务器、顶级域(TLD)DNS服务器和权威DNS服务器。它们的关系如下图:
以请求www.baidu.com的IP为例:主机首先与某个根服务器联系,根据顶级域名com返回对应的com顶级域服务器的ip地址;然后再访问TLD服务器获取baidu.com的权威服务器的ip地址;最后访问权威服务器后获取www.baidu.com对应主机的ip地址。
总结起来这三类服务器作用是从高到低逐渐定位到某个服务器,将域名逐步细化从而得到某个主机的ip。根服务器提供TLD服务器的IP,而TLD服务器提供权威服务器的IP,最后权威服务器提供该URL对应主机的IP。平时我们常见的顶级域有org、com、gov、.net和edu等,国家也有对应顶级域如中国cn、法国fr等。权威服务器负责存储一个公共的DNS记录,以便访问该权威服务器的客户能够将主机名映射为IP地址。
但是现实生活中我们往往还会在主机后连接上一个代理DNS服务器称为本地DNS服务器。它是由ISP机构提供,主要作用是为我们查询IP时起到代理的作用。同时本地DNS服务器也和Web缓存器有类似的作用,都能够缓存下一些主机名/IP的地址对。这样当另一台主机请求相同的主机名时,本地DNS服务器能够快速做出反应。一个常见的IP请求如下图所示:
当我们请求某个主机名的IP时,我们一把不会直接发送请求报文给根DNS服务器,而会先发送给本地的代理DNS服务器,让它代理我们获取最终查询到的主机名IP。这也说明现实往往不是简单的模型,显示要往往复杂得多:TLD也不一定知道权威DNS服务器的IP,它们之间可能也隔着很多DNS服务器;IP查询的方式也可能不是这样查询,也可能如下图那样查询。
我们称DNS的分布式数据库存储的是DNS服务器的资源记录(RR),RR用于记录主机名到IP的映射,所以我们请求获取的回答报文一般就包括RR。RR是一个包含了四个字段(Name,Value,Type ,TTL)的4元组。TTL是记录的生存时间,一旦到时间就删除掉该资源记录。正常工作的情况下,Name和Value取决于Type的值。
一般情况下,DNS的权威服务器会存储一条A类型的RR,它记录的无疑就是对应主机的名和IP地址;而对于非DNS权威服务器而言,例如TLD,一般它会分别包括一条NS和A类型的RR,NS类型的RR记录域对应的DNS权威服务器的主机名,而A记录着该权威服务器主机名的IP。通俗来说就是一条可以将域映射为权威服务器的主机名的RR和一条将该权威服务器的主机名映射为IP的RR,做了两次转换(域->主机名->ip)。
DNS的报文分为两种:查询报文和回答报文,这两种报文的格式都是采用下图的格式:
报文前面12个字节的部分称为首部区域,标识符占16个比特,用于标识查询报文,这个标识符会复制到对应的回答报文以此便于匹配查询报文和回答报文。标志是若干个标志位组成,例如1bit标志位可以标准是查询/回答报文;1bit可以用于标准是否递归查询...剩下的4组数将决定下面的4个数据区域对应的数量。
下面是问题区域,主要对应查询报文,这个区域包含两个字段:记录被查询的主机名的名字字段(Name)和记录查找的问题类型的类型字段(Type)。
接下来的是回答区域,它记录的是请求的名字对应的资源记录,包括Type字段、Value字段和TTL字段。它甚至可以返回多个RR(因为一个主机名可能对应多个IP地址)。
最后是权威区域和附加信息,它们记录其它权威服务器的记录和增添一些有帮助的记录。
因特网的电子邮件系统由三部分组成:用户代理、邮件服务器和邮件传输协议(SMTP)。用户代理是用户写邮件、回复邮件、发邮件、保存邮件的地方。写好的邮件发送到邮件服务器的外出报文队列,由邮件服务器发送到对方邮箱所在的邮件服务器,等发送到对方邮箱后对方就可以读取邮件。
SMTP是因特网电子邮件传输协议,它是一个推协议,即一有信息发送方将文件推向服务器(拉协议是需要时才加载信息),同时它限制邮件报文只能采用7比特的ASCII表示(C语言中常用的ASCII标准)。下面的例子是书上一个客户C和SMTP服务器S之间的传输过程:
其中HELO、MAIL FROM、RCPT TO、DATA、QUIT都是客户发送的自解释的SMTP指令,这些命令也是对话的一部分。而邮件服务器端会返回一些回答码和英文提示。整个对话结束标准是一个另开一行的点。HELO是和服务器打招呼表明身份的命令,而MAIL FROM是指邮件来源的命令,RCPT TO是发送对象的指令,QUIT是结束指令,DATA是开始写内容的命令...这些命令都是以英文形式确立的,比较好认。
前面的SMTP指令是用于建立连接,而下面就是我们要写的报文的格式内容了,我们邮件报文也要在内容之前加上知名发送人和接收人的首部行,不过与前面的SMTP指令的用处(建立握手协议)不同,邮件报文的首部行是邮件的内容的一部分。我们需要在邮件的报文的首部行夹杂一些环境信息。例如From:首部行、To:首部行和Subject:首部行等三个首部行,其中前两个是必须的,再加一个空白就可以输入内容了。上述的内容都是在前面SMTP的基础上的DATA指令后输入的内容。与前面结合差不多是这样
邮件访问协议的产生是因为当我们收到一封信后,我们是有空时才去同各国邮件代理连接邮件服务器去读取该信。但是读取信的过程是随机的,也就是所原来的SMTP协议不合适,因为它是一个推协议。为此引入一个特殊的拉协议也就是邮件访问协议来规定读取邮件的过程。常见的邮件访问协议有第三版的邮局协议(POP3)和因特网邮件访问协议(IMAP)和HTTP协议。
与传统的C/S体系不同,P2P体系是应用程序另一种类型的网络结构。因为在用户间可以互相通信的缘故,P2P体系的存在能够极大减少服务器的压力。而P2P体系常用到的协议就是BitTorrent协议。
BitTorrent是P2P模式中最常见的文件分发协议。我们知道,P2P模式允许客户之间相互传输文件,所以标准规定参与某个文件分发的所有主机(对等方)的集合称为洪流(torrent)。用户之间相互下载等大小(典型为256KB)的文件块。当我们取得对应文件的所有文件块时,我们就可以选择退出当前洪流,或留下来继续为其它对等方上传我们有的文件块。
但是庞大的对等方集合不能没有管理,于是在洪流网络中引入了追踪器。当一个主机试图加入洪流时,它需要向追踪器注册自己,定时向追踪器报告,并且离开时也需要告知追踪器。当追踪器得知有新主机加入后,它会随即从洪流中选择部分(通常为50个)对等方集合(这些对等方也成为邻近对等方),并且将这些对等方的IP发送给新加入的主机,然后新加入的主机就可以和这些原有的对等方之间建立TCP连接并且通信了,当然,这些对等方也可能随着时间而减少,所以主机需要定时咨询和更新对等方,以获得完整的文件块。
但是面对庞大的分发网络,客户机如何保证能够更有效率地获取完整文件呢?为了解决这个问题,于是客户机选择时就有下面的两个决定原则:最稀缺优先和最高速优先。
最稀缺优先就是指在我们文件未下载完的那些文件块中我们主机会优先从邻近对等方中获取最少的那些文件块(邻近对等方中副本最少的),以此保证文件块在网络中能够保持合理的数量。
最高速优先是指我们客户机优先和能够向我们提供最大传输速率的邻近对等方建立运输链接。我们客户机和周期性地选择一个最合适(运输速率最大)的伙伴来进行运输链接。
每天都会有大量的视频流通,我们不可能采取单一的服务器存储所有的视频,这样会导致很多问题:如果服务器损坏,将彻底无法提供服务;如果客户机里服务器过远,那么可能会导致时延过大;相同的视频被反复传输,成本高。为了解决视频的传输问题,现代视频流传输常采用CDN传输体系。
内容分发网(Content Distribution network,CDN),它负责管理存储视频不同地理位置的服务器,可以将客户请求定位到附近服务器。CDN可以是某个提供视频流服务的供应商所有的专用CDN,也可以是第三方专门提供CDN服务的第三方CDN。
CDN的服务器安放也是有原则的,常见的就是深入和邀请做客原则。深入原则就是直接将CDN的服务器集群放置到接入ISP中,以此尽量靠近用户,这样做极大减少时延,但是却增加了维护的难度。邀请做客原则就是在少量关键位置如IXP交换点处放置大型的服务器集群,这样做虽然减少维护和管理的费用,但是却增加了传输时延。其实无论是哪种安放原则,我们的视频都不是推进服务器集群中,而是有某个视频的需求时,如果服务器没有缓存,服务器会将其“拉”进来,它具体的工作方式类似于Web的缓存器。
那么具体来说,当我们通过URL请求某个视频时,CDN的具体工作就是:
1、首先将我们的请求截取,求出离我们附近的服务器集群以便于快速传输;
2、然后会通过我们的请求帮助我们定位到某个服务器集群的某台服务器。
但是现实生活中CDN的服务往往DNS挂钩,这样CDN就可以通过我们本地的DNS服务器来确定我们的IP所在地,选取地理位置较近的CDN服务器集群为我们提供服务,以我们请求某个视频为例,这个视频供应商是A公司,它使用第三方公司B的CDN服务器。
我们在浏览网页时点击了某个视频,那么我们的主机会发出对应这个视频URL的DNS请求。本地DNS服务器接收到后会根据域名将DNS请求报文中继到A公司的权威DNS服务器,此时A公司的权威DNS服务器并不返回IP地址,而是返回一个B公司的域里的主机名,然后本地DNS服务器再和B公司的权威服务器通信,获取之前得到的B公司的域里的主机名对应的IP地址,最后访问B公司的内容分发服务器即可获取视频资料。
参考资料:《计算机网络-自顶向下方法第七版》