应用层 ######################################## 应用与应用层协议 **************************************** .. csv-table:: 流行的互联网应用及其支撑协议 :header: 应用, 应用层协议, 运输协议 :align: center 电子邮件, SMTP [ :rfc:`5321` ], TCP 远程终端访问, Telent [ :rfc:`854` ], TCP Web, HTTP [ :rfc:`2616` ], TCP 文件传输, FTP [ :rfc:`959` ], TCP 流媒体, HTTP, TCP 因特网电话, SIP [ :rfc:`3261` ]、RTP [ :rfc:`3550` ] 或专用的(如Skype), UDP或TCP HTTP **************************************** .. seealso:: - HTTP1.0::rfc:`1945` - HTTP1.1::rfc:`2616` - HTTP2.0::rfc:`7540` - HTTP3.0:\ `HTTP3 `_ (实验性) HTTP(超文本传输协议)是互联网Web服务的核心协议。HTTP由两个程序实现:服务器程序和客户端程序,两者通过交换 ``HTTP报文`` 进行会话。 Web页面由对象构成,每个被引用的文件(html、img、mp4)都是一个对象。 .. attention:: #. HTTP运行于TCP之上而不是UDP。 #. HTTP是一个 ``无状态协议`` ,服务端不保存客户端的任何信息。 非持续连接和持续连接 ======================================== 非持续连接和持续连接的唯一不同在于服务器和客户端之间时候会维护已建立的TCP连接。 - 非持续连接的每个TCP连接仅传递一个对象,对象接受后立即销毁TCP连接。 - 持续连接在建立TCP连接后的一段时间内维护TCP连接,当超时不用后,TCP连接将被销毁。 由于此种方式,非持续连接和持续连接具有一下特点: 定义一个短分组从客户机到服务器然后再返回客户机所用的时间为一个 ``RTT`` (Round-Trip, 往返时间)。则建立TCP连接需要一个RTT。 .. note:: RTT包括了分组的传播时延、排队时延、分组处理时延 .. important:: #. 非持续连接在接受每个对象是需要分别建立一个TCP连接并接受一个对象,共花费1 RTT。而持续连接只需要起始时建立一个TCP连接。 #. 对每次连接,客户机和服务机都必须分配发送和接收缓存。这就意味着要影响客户机和服务机的存储器资源,这同样要占用CPU的时间。 [#]_ #. 对由大数量对象组成的文件,TCP的低速启动算法(slow start-up algorithm)会限制服务机向客户机传送对象的速度。使用持续连接之后,大多数对象都可以尽最大的速率传送。 #. HTTP1.0使用的是非持续连接。而HTTP1.1默认为持续连接,也可以配置为非持续连接。 HTTP请求报文 [#]_ ======================================== 一个HTTP请求报文如下: :: GET https://www.baidu.com HTTP/1.1 Host: www.baidu.com User-Agent: Mozilla/5.0 Accept: text/plain Accept-Language: zh-CN Accept-Encoding: gzip Connection: keep-alive Cookie: (some string) (some data ...) 格式如下: .. image:: assets/应用层_HTTP_请求报文格式.png 请求报文之间的换行为 :kbd:`cr` :kbd:`lf` ( ``\r\n`` )。 HTTP请求报文的第一行为 ``请求行`` , 后继部分为 ``首部行``。 请求行的三个字段分别为 ``请求方法字段`` 、 ``URL字段`` 、 ``HTTP版本字段`` 方法字段可以为: ``GET`` 、``POST``、``HEAD``、``PUT``、``DELETE`` 跟随在请求行和首部行之后的是 ``实体体``,当向服务器提交 ``表单`` 时需要用到。``GET`` 方法绝对不会用到实体体,一般情况下使用 ``POST`` 向服务器提交表单时会用到。 .. note:: 向服务器提交表单并非一定要使用 ``POST`` 方法,也可以使用 ``URL`` 进行提交。例如: https://www.baidu.com/baidu?ie=utf-8&wd=network 向baidu.com提交了 ``ie=utf-8`` 和 ``wd=network`` 两个表单。 HTTP响应报文 ======================================== 一个HTTP响应报文格式如下: :: HTTP/1.1 200 OK\r\n Connection: keep-alive\r\n Date: Wed, 25 Mar 2020 03:18:42 GMT\r\n Server: Tengine\r\n Last-Modified: Wed, 25 Mar 2020 00:00:00 GMT\r\n Content-Length: 1574\r\n Content-Type: application/ocsp-response\r\n 格式如下: .. image:: assets/应用层_HTTP_响应报文格式.png #. HTTP常见状态码如下: - 200 OK:请求成功 - 301 Moved Permanently:请求对象已经被永久转移了,新的URL定义在响应报文的首部行的Location中。 - 400 Bad Request:请求报文无法被服务器理解 - 404 Not Found:请求的内容无法找到 - 505 HTTP Version Not Support .. seealso:: - `HTTP状态码 `_ - :rfc:`2616` 、:rfc:`2518`、 :rfc:`2817`、 :rfc:`2295`、 :rfc:`2774`、 :rfc:`4918` .. seealso:: #. `HTTP请求报文和HTTP响应报文 `_ HTTP 请求方式 ======================================== +------------------+-------------------------------------------------------------+ | 方式 | 说明 | +==================+=============================================================+ | GET | 请求指定的页面信息,并返回实体主体。 | +------------------+-------------------------------------------------------------+ | HEAD | 只请求页面的首部。 | +------------------+-------------------------------------------------------------+ | POST | 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体。 | +------------------+-------------------------------------------------------------+ | PUT | 从客户端向服务器传送的数据取代指定的文档的内容。 | +------------------+-------------------------------------------------------------+ | DELETE | 请求服务器删除指定的页面。 | +------------------+-------------------------------------------------------------+ | OPTIONS | 允许客户端查看服务器的性能。 | +------------------+-------------------------------------------------------------+ | TRACE | 请求服务器在响应中的实体主体部分返回所得到的内容。 | +------------------+-------------------------------------------------------------+ | PATCH | 实体中包含一个表,表中说明与该URI所表示的原内容的区别。 | +------------------+-------------------------------------------------------------+ | MOVE | 请求服务器将指定的页面移至另一个网络地址。 | +------------------+-------------------------------------------------------------+ | COPY | 请求服务器将指定的页面拷贝至另一个网络地址。 | +------------------+-------------------------------------------------------------+ | LINK | 请求服务器建立链接关系。 | +------------------+-------------------------------------------------------------+ | UNLINK | 断开链接关系。 | +------------------+-------------------------------------------------------------+ | WRAPPED | 允许客户端发送经过封装的请求。 | +------------------+-------------------------------------------------------------+ | Extension-mothed | 在不改动协议的前提下,可增加另外的方法。 | +------------------+-------------------------------------------------------------+ HEAD 方法跟 GET 方法相同,只不过服务器响应时不会返回消息体。一个 HEAD 请求的响应中,HTTP 头中包含的元信息应该和一个GET请求的响应消息相同。这种方法可以用来获取请求中隐含的元信息,而不用传输实体本身。也经常用来测试超链接的有效性、可用性和最近的修改。 一个 HEAD 请求的响应可被缓存,也就是说,响应中的信息可能用来更新之前缓存的实体。如果当前实体跟缓存实体的阈值不同(可通过 Content-Length、Content-MD5、ETag 或 Last-Modified 的变化来表明),那么这个缓存就被视为过期了。 HEAD请求常常被忽略,但是能提供很多有用的信息,特别是在有限的速度和带宽下。主要有以下特点: - 只请求资源的首部; - 检查超链接的有效性; - 检查网页是否被修改; - 多用于自动搜索机器人获取网页的标志信息,获取rss种子信息,或者传递安全认证信息等 HEAD 方法:它与 GET 方法几乎是一样的,对于 HEAD 请求的回应部分来说,它的 HTTP 头部中包含的信息与通过 GET 请求所得到的信息是相同的。利用这个方法,不必传输整个资源内容,就可以得到 Request-URI 所标识的资源的信息。该方法常用于测试超链接的有效性,是否可以访问,以及最近是否更新。 +--------+--------------------------------------------+ | 错误码 | 说明 | +========+============================================+ | 1xx | 指示信息--表示请求已接收,继续处理。 | +--------+--------------------------------------------+ | 2xx | 成功--表示请求已被成功接收、理解、接受。 | +--------+--------------------------------------------+ | 3xx | 重定向--要完成请求必须进行更进一步的操作。 | +--------+--------------------------------------------+ | 4xx | 客户端错误--请求有语法错误或请求无法实现。 | +--------+--------------------------------------------+ | 5xx | 服务器端错误--服务器未能实现合法的请求。 | +--------+--------------------------------------------+ 常见状态代码、状态描述的说明如下。 +---------------------------+---------------------------------------------------------------------------------------------+ | 状态码 | 说明 | +===========================+=============================================================================================+ | 200 OK | 客户端请求成功。 | +---------------------------+---------------------------------------------------------------------------------------------+ | 400 Bad Request | 客户端请求有语法错误,不能被服务器所理解。 | +---------------------------+---------------------------------------------------------------------------------------------+ | 401 Unauthorized | 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用。 | +---------------------------+---------------------------------------------------------------------------------------------+ | 403 Forbidden | 服务器收到请求,但是拒绝提供服务。 | +---------------------------+---------------------------------------------------------------------------------------------+ | 404 Not Found | 请求资源不存在,举个例子:输入了错误的URL。 | +---------------------------+---------------------------------------------------------------------------------------------+ | 500 Internal Server Error | 服务器发生不可预期的错误。 | +---------------------------+---------------------------------------------------------------------------------------------+ | 503 Server Unavailable | 服务器当前不能处理客户端的请求,一段时间后可能恢复正常,举个例子:HTTP/1.1 200 OK(CRLF)。 | +---------------------------+---------------------------------------------------------------------------------------------+ .. seealso:: - `HTTP head请求 - longyongzhen - 博客园 `_ Cookie ======================================== HTTP服务器是无状态的,这简化了服务器的设计,但是另一方面也导致服务器无法识别用户。为了识别用户 ``cookie`` 技术应运而生。 Cookie定义于 :rfc:`6265` 。包含了四个组件: #. HTTP响应报文中的cookie首部行 #. HTTP请求报文中的cookie首部行 #. 在客户端保存的cookie文件 #. 位于HTTP服务器的数据库 服务器在客户端第一次请求网页时在 ``响应头`` 使用 ``set-cookie`` 设置cookie, 此后每当客户端向服务器请求网页时,都会在 ``请求头`` 中添加已经设置的 ``cookie``。 通过此种方法,服务器达到了追踪客户端的目的。 .. attention:: 响应头可以通过多行 ``set-cookie`` 来设置cookie, 而请求头则将 cookie写为一行(通过 ``;`` 隔开) .. seealso:: `Set-Cookie `_ HTTP 2.0 ======================================== - HTTP 2.0 所有通信都在一个 TCP 连接上完成。 - HTTP 2.0 浏览器可以在发现资源时立即分派请求,指定每个流的优先级,让服务器决定最优的响应次序。 - HTTP 2.0 支持服务器到客户端的主动推送机制。 - HTTP/2.0 通过支持首部字段压缩和在同一连接上发送多个并发消息,让应用更有效地利用网络资源,减少感知的延迟时间。 .. seealso:: - `HTTP 2.0 协议详解 `_ DNS **************************************** DNS 分为三部分:层次域名空间、域名服务器、解析器 DNS 协议运行在 53 号端口的 UDP 之上。其原因是多次 DNS 请求都返回相同的结果,即做多次和做一次的效果是一样的,因此 DNS 操作可以重复执行,若分组丢失,那么可以再请求一次,这样不会有任何害处,而且使用 UDP 可以让 DNS 服务器接收更多的连接。 .. note:: 如果一台主机通过多个网卡连接到多个网络,那么就可以具有多个 IP 地址,每块网卡都有一个 MAC 地址,这些网卡可以同时连接到不同的网络上(网络号不能相同,否则会发生冲突)。多台主机可以映射到一个域名上(负载均衡),一台主机也可以映射到多个域名上(虚拟主机) 域名服务器 ======================================== 1. 根域名服务器:所有的根域名服务器都知道所有的顶级域名服务器的 IP 地址 2. 顶级域名服务器:这些服务器负责在该顶级域名服务器下注册的所有二级域名 3. 授权域名服务器(权限域名服务器):授权域名服务器 ``一定`` 能将其管辖的 **主机名** 转换为该主机的 IP 地址 4. 本地域名服务器:本地域名服务器负责解析本地局域网内所有的域名解析 域名解析过程 ======================================== 域名解析分为两种: - 正向解析:将域名映射为 IP 地址 - 反向解析:将 IP 地址映射为域名 域名解析的方式有两种: - 递归查询:每台客户机只需要向域名服务器查询一次 DNS,服务器递归进行查询 IP 查询,并层层传递 - 递归和迭代相结合:主机向本地域名服务器查询一次,但本地域名服务器根据需要可能会查询多个域名服务器 高速缓存 ======================================== 高速缓存有一下几个用处: - 提高 DNS 的查询效率 - 减少因特网上 DNS 查询报文数量 FTP **************************************** 文件传输协议( :abbr:`FTP (File Transfer Protocol)` )具有以下特点: - 允许客户指名文件的类型和格式 - 允许文件具有存取权限 - 允许通过 ``anonymous`` 账户进行公用文件共享能力 - 提供跨越软件和硬件的文件传输能力 - 在整个会话期间保留用户的状态信息 FTP 使用两个端口实现文件传输能力: 20-FTP 端口用于传输数据、 21-FTP 端口控制连接。其具有以下优点: - 实现简单 - 可以在传输文件时使用控制端口终止文件传输 电子邮件 **************************************** 在电子邮件系统由 ``用户代理`` 、``邮件服务器`` 和 ``邮件协议`` 三者组成。其中邮件协议如下: .. csv-table:: 邮件相关协议 :header: 协议, RFC, 底层协议, 保留端口 :align: center SMTP_, :rfc:`5321`, TCP, 25 POP3_, :rfc:`1939`, TCP, 110 IMAP_, :rfc:`3501`, TCP, TCP ``用户代理`` 代表了用户使用的邮件客户端 电子邮件交互各个阶段用到的协议如下: .. image:: assets/邮件发送各阶段协议.png :scale: 70 SMTP ======================================== SMTP(Simple Mail Transfer Protocol, 简单邮件传输协议), 可用于用户代理向邮件服务器上传邮件、邮件服务器之间发送邮件。 SMTP有一下特性: - SMTP只能传送7位ASCII编码。这意味SMTP的所有报文必须编码为ASCII编码,这是一个历史遗留问题。 - SMTP一般情况下不使用中间服务器。 - 报文行长度≤78字符(不包括cflf) - 报文总长度≤998字符 .. seealso:: - `协议基础:SMTP:使用Telnet学习SMTP协议 `_ - `SMTP协议介绍 `_ POP3 ======================================== POP3(Post Office Portocol version 3, 第三版邮局协议)。用于从服务器获取邮件。POP3是一个简单的邮件协议,功能有限,其工作步骤如下: #. 特许:邮件服务器通过用户代理发送的明文形式的用户名和口令进行认证。 #. 事务处理:用户代理获取邮件、标记需要删除的邮件、获取邮件的统计信息。 #. 更新阶段:结束POP3会话并删除被标记的邮件。 POP3服务器回答有两种状态:``+OK`` 和 ``-ERR`` 一个POP会话如下: :: $> telnet pop.163.com 110 Trying 123.126.97.79... Connected to pop.163.com. Escape character is '^]'. S: +OK Welcome to coremail Mail Pop3 Server (163coms[10774b260cc7a37d26d71b52404dcf5cs]) C: user [用户名] S: +OK core mail pass [口令] S: +OK 1 message(s) [7821 byte(s)] list S: +OK 1 7821 1 7821 . C: retr 1 S: +OK 7821 octets [邮件描述及其内容] C: noop S: +OK core mail C: quit S: +OK core mail $> Connection closed by foreign host. .. seealso:: - `POP3协议分析 `_ - `POP3协议详细介绍(一) `_ IMAP ======================================== IMAP(Internet Mail Access Protocol, 互联网邮件访问协议)是一个比POP3功能更丰富、实现更复杂的协议。 相比POP3,IMAP提供了以下几种主要特性: - 通过会话建立、删除、移动远程文件夹 - 维护IMAP会话用户状态信息 - 允许获取邮件报文的特定部分 编程实践:创建一个 HTTP 服务器 **************************************** 要创建一个 HTTP 服务器,我们只需要以下几个组件: #. 使用 TCP 监听端口号 #. 在接到连接请求后向套接字发送 ``响应报文`` 代码如下: .. code-block:: python from socket import * serverSocket = socket(AF_INET, SOCK_STREAM) serverSocket.bind(("localhost", 12000)) # 监听本地端口 12000 serverSocket.listen(1) # 响应内容 head =\ "HTTP/1.1 200 OK \r\n" \ "Content-Type: text/plain\r\n" \ "\r\n" \ "Hello, World" while True: connectSocket, addr = serverSocket.accept() msg = connectSocket.recv(1024) print(msg) print(addr) connectSocket.send(head.encode()) connectSocket.close() 这样,当你在浏览器中键入 ``localhost:12000`` 时,浏览器会创建一条 TCP 连接,并 ``随机绑定一个端口号`` 来与你的服务器进行通信。随后你的服务器将会返回响应内容,并被浏览器打开。 其中 ``Content-Type`` 代表了数据代表的 **MIME 类型** ,MIME 被定义在 :rfc:`822`, :rfc:`2045`, :rfc:`2046` , :rfc:`2047` , :rfc:`2048` , :rfc:`2049` . [#]_ .. [#] `HTTP协议的持续连接和非持续连接 `_ .. [#] `深度理解HTTP请求报文和HTTP响应报文 `_ .. [#] `MIME 参考手册 `_