本篇从应用开发者的角度介绍进程通信、运输服务需求,以及 Web 与 HTTP/1.x 的连接和报文机制。Cookie、缓存及后续协议见 Chapter 2.2 Application Layer 2。

2.1 网络应用的基本原理

开发网络应用,主要是在不同端系统上编写相互交换消息的程序,例如浏览器与 Web 服务器。普通网络核心负责转发,通常不需要为每种新应用改写路由器代码。

2.1.1 应用体系结构

在规定消息格式之前,先确定哪些进程承担服务、它们如何找到彼此,以及数据经过哪些参与方。

结构参与方如何组织主要特点
客户端—服务器(client-server)客户端向持续运行、具有稳定可达地址的服务器请求服务易于集中管理;扩展时可使用服务器集群
对等结构(P2P)对等端直接交换数据,也可同时向其他端提供资源能利用参与者的资源扩展服务;节点上下线和地址变化增加管理难度
混合结构集中服务负责发现、登录等功能,端之间直接传数据将集中协调与端间通信结合

在基本客户端—服务器模型中,客户端可能间歇上线、使用动态地址,通常通过服务器交互。纯 P2P 不依赖始终在线的中心服务器;实际系统也可能只在部分功能中采用 P2P。

2.1.2 进程、socket 与寻址

网络最终连接的是运行中的应用进程。仅知道数据应到哪台主机,还不足以确定应交给其中哪个应用。

定义:进程与通信角色

进程(process)是主机上运行的程序。同一主机上的进程通过操作系统提供的进程间通信机制交互;不同主机上的进程通过网络交换消息。

在一次通信中,主动发起联系的称为客户端进程,等待被联系的称为服务器进程。P2P 应用中也存在这两种角色。

定义:套接字(Socket)

应用进程使用运输层服务的接口。进程通过 socket 发送和接收消息,将数据交给下层传输,或取得下层交付的数据。

socket 像应用的“门”:开发者控制应用侧的逻辑,可以选择运输协议、设置部分参数;运输机制的主要实现由操作系统负责。

在确定运输协议的语境下,通信端点需要由 IP 地址和端口号共同标识:

  • IP 地址定位网络中的主机接口;IPv4 地址长度为 32 bit。
  • 端口号区分该主机上的不同通信服务或端点。

例如,传统 HTTP 服务常使用 TCP 80 端口,服务器间 SMTP 常使用 TCP 25 端口。同一个 IP 地址上可以同时运行多种服务,不能只靠 IP 地址确定接收进程。

2.1.3 应用层协议规定什么

确定参与方和通信端点后,还需要让双方对消息及其处理方式有共同理解。

应用层协议规定四类内容:

  1. 消息类型:例如请求、响应。
  2. 消息语法(syntax):包含哪些字段,字段如何分隔。
  3. 消息语义(semantics):各字段表达什么含义。
  4. 交互规则:何时发送消息、如何响应收到的消息。

HTTP、SMTP 等公开协议有可查阅的规范,便于不同实现互通;应用也可以采用专有协议。

2.1.4 应用需要哪些运输服务

运输层的选择取决于应用需求。“每个字节都要到达”“要及时到达”和“单位时间要收到足够多的数据”是不同的要求。

需求维度关心的问题典型差异
可靠性/数据丢失是否允许交给应用的数据缺失或出错文件传输需要完整正确;实时音视频可能容忍少量损失
时延(timing)数据是否能及时到达交互游戏、实时通话对时延敏感
吞吐量(throughput)数据能否以足够的速率持续交付音视频需要一定速率;弹性应用可利用获得的可用速率

弹性应用(elastic application)不要求固定的最低吞吐量:速率低时可以完成得慢一些。实时应用即使平均吞吐量足够,也可能因延迟过高而无法正常交互。

应用可靠性需求吞吐量特点对时间的要求
文件下载、邮件、Web 文档需要可靠交付通常是弹性的对严格截止时间要求较弱
实时音视频可容忍有限损失需要支持相应编码速率对低时延要求强
存储音视频流可容忍一定损失或由机制补偿需要维持播放速率可用缓冲吸收部分延迟
交互游戏取决于具体消息,可容忍部分损失速率要求因应用而异对低时延要求强
文本消息通常需要可靠交付通常是弹性的对及时性的要求取决于场景

2.1.5 TCP 与 UDP 的服务

Internet 提供 TCP、UDP 等运输服务,但它们的基础服务都不保证“在指定时间内得到指定带宽”。

服务特性TCPUDP
连接建立通信前需建立连接无需建立运输层连接
可靠交付提供可靠、有序的字节流服务不保证交付、次序或去重
流量控制避免发送端压垮接收端本身不提供
拥塞控制网络拥塞时调节发送本身不提供
时延/最低吞吐量保证不提供不提供

流量控制面向接收端承受能力,拥塞控制面向网络负载,两者目的不同。TCP 的可靠性也不意味着面对连接失败仍能无限保证交付。

UDP 的机制较少,应用可以自行决定时序、恢复与控制方式,例如实时应用可能更希望及时处理后续数据,而非等待过期数据重传。应用也可以在 UDP 之上实现可靠传输与拥塞控制,后面的 QUIC 就是例子。

传统 FTP、SMTP 和 HTTP/1.x 使用 TCP;实时通信、游戏可按需求使用 TCP 或 UDP。应用协议与运输协议属于不同层,不能仅凭“传音视频”就断言一定使用 UDP。

2.2 Web 与 HTTP

Web 展示了应用如何通过请求与响应获取对象;之后的连接复用、Cookie 和缓存,分别解决连接开销、跨请求状态与重复传输的问题。

2.2.1 Web 对象与请求—响应模型

一个网页通常由基本 HTML 文件和其中引用的其他对象组成,例如图片、音频、脚本等。每个对象可以通过 URL 定位。

HTTP(Hypertext Transfer Protocol)采用客户端—服务器模型:浏览器发送请求,Web 服务器返回响应。下面先用 HTTP/1.x、TCP 80 端口的基本模型分析,再讨论 HTTP/2 和 HTTP/3。

HTTP 是无状态(stateless)的:协议本身不要求服务器为了处理本次请求而记住此前的请求历史。它不妨碍应用另外使用 Cookie、会话和数据库保存状态。

2.2.2 非持续连接与响应时间

早期非持续 HTTP 为每个对象建立独立 TCP 连接,传完后关闭;获取同一个页面引用的多个对象,会重复承担连接建立开销。

定义:RTT(Round-Trip Time,往返时间)

一个很小的分组从客户端到服务器,再返回客户端所需的时间。HTTP 的简化分析用 RTT 表示一次往返交互的时延。

对一个大小为 bit 的对象,设有效传输速率为 bit/s,忽略 DNS、服务器处理、TLS、请求发送时间等开销,则

其中约一个 RTT 用于建立 TCP 连接,一个 RTT 用于发出 HTTP 请求并等到响应开始返回, 用于传输对象。第二个 RTT 已计入请求与响应的往返传播,不要另加一遍相同的传播开销。

2.2.3 持续连接与流水线

为了避免每个对象都重新建立连接,HTTP/1.1 默认采用持续连接(persistent connection),让多个请求—响应复用同一条 TCP 连接。

方式后续请求何时发送简化的往返开销
非持续连接每个对象使用新连接每个对象约两个 RTT,另加传输时间
持续连接、不使用流水线前一个响应收齐后再发下一个请求已有连接上,每个对象约一个 RTT,另加传输时间
持续连接、使用流水线不等待前一响应,连续发送多个请求一批已知对象可共享等待往返的开销,仍需传输对象

HTTP/1.1 的流水线(pipelining)要求响应按请求次序返回。若前面的响应很大,后面的短响应仍要等待,这为后面的 HTTP/2 引出了问题。

持续连接与流水线是两个概念:HTTP/1.1 默认持续连接,不表示客户端一定启用流水线。即使把多个请求连续发出,也不意味着多个对象的传输时间消失。

2.2.4 HTTP/1.x 报文

连接提供字节传输,HTTP 还要约定如何从字节中识别请求、状态、首部与内容。HTTP/1.x 的请求行和首部采用文本格式,消息体则可以承载二进制对象。

一个请求包含请求行、首部行、空行,以及可选的消息体:

GET /course/index.html HTTP/1.1
Host: www.example.edu
Connection: close
Accept-Language: zh-CN
 

请求行依次给出方法、请求目标和协议版本;Host 指定目标主机;Connection: close 表示请求在响应后关闭连接。首部行使用 CRLF(回车、换行)结束,空行标志首部结束,不能省略。

方法基本用途
GET请求取得资源的表示
POST提交数据,由目标资源处理
HEAD与 GET 类似,但响应不携带消息体
PUT请求用消息体创建或替换目标资源的表示
DELETE请求删除目标资源

响应包含状态行、首部、空行与可选消息体:

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 13
Connection: close
 
Hello, world!

状态行给出版本、状态码和原因短语;Content-Type 表示内容类型,Content-Length 表示消息体的字节长度。状态码告诉客户端请求结果:

状态码含义
200 OK请求成功
301 Moved Permanently资源永久迁移,新位置通常由 Location 指出
400 Bad Request请求存在语法等问题,服务器无法按要求处理
404 Not Found没有找到请求资源
505 HTTP Version Not Supported服务器不支持请求使用的 HTTP 版本