本篇从应用开发者的角度介绍进程通信、运输服务需求,以及 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 应用层协议规定什么
确定参与方和通信端点后,还需要让双方对消息及其处理方式有共同理解。
应用层协议规定四类内容:
- 消息类型:例如请求、响应。
- 消息语法(syntax):包含哪些字段,字段如何分隔。
- 消息语义(semantics):各字段表达什么含义。
- 交互规则:何时发送消息、如何响应收到的消息。
HTTP、SMTP 等公开协议有可查阅的规范,便于不同实现互通;应用也可以采用专有协议。
2.1.4 应用需要哪些运输服务
运输层的选择取决于应用需求。“每个字节都要到达”“要及时到达”和“单位时间要收到足够多的数据”是不同的要求。
| 需求维度 | 关心的问题 | 典型差异 |
|---|---|---|
| 可靠性/数据丢失 | 是否允许交给应用的数据缺失或出错 | 文件传输需要完整正确;实时音视频可能容忍少量损失 |
| 时延(timing) | 数据是否能及时到达 | 交互游戏、实时通话对时延敏感 |
| 吞吐量(throughput) | 数据能否以足够的速率持续交付 | 音视频需要一定速率;弹性应用可利用获得的可用速率 |
弹性应用(elastic application)不要求固定的最低吞吐量:速率低时可以完成得慢一些。实时应用即使平均吞吐量足够,也可能因延迟过高而无法正常交互。
| 应用 | 可靠性需求 | 吞吐量特点 | 对时间的要求 |
|---|---|---|---|
| 文件下载、邮件、Web 文档 | 需要可靠交付 | 通常是弹性的 | 对严格截止时间要求较弱 |
| 实时音视频 | 可容忍有限损失 | 需要支持相应编码速率 | 对低时延要求强 |
| 存储音视频流 | 可容忍一定损失或由机制补偿 | 需要维持播放速率 | 可用缓冲吸收部分延迟 |
| 交互游戏 | 取决于具体消息,可容忍部分损失 | 速率要求因应用而异 | 对低时延要求强 |
| 文本消息 | 通常需要可靠交付 | 通常是弹性的 | 对及时性的要求取决于场景 |
2.1.5 TCP 与 UDP 的服务
Internet 提供 TCP、UDP 等运输服务,但它们的基础服务都不保证“在指定时间内得到指定带宽”。
| 服务特性 | TCP | UDP |
|---|---|---|
| 连接建立 | 通信前需建立连接 | 无需建立运输层连接 |
| 可靠交付 | 提供可靠、有序的字节流服务 | 不保证交付、次序或去重 |
| 流量控制 | 避免发送端压垮接收端 | 本身不提供 |
| 拥塞控制 | 网络拥塞时调节发送 | 本身不提供 |
| 时延/最低吞吐量保证 | 不提供 | 不提供 |
流量控制面向接收端承受能力,拥塞控制面向网络负载,两者目的不同。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 定位。
例子:网页不等于一个对象
对 URL
http://www.example.edu/course/pic.gif,www.example.edu是主机名,/course/pic.gif是路径。若一个 HTML 页面引用 10 张图片,浏览器取得 HTML 后,还需要请求这些引用对象;取得 HTML 不等于已经取得整个网页的全部内容。
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 已计入请求与响应的往返传播,不要另加一遍相同的传播开销。

补充例题:顺序获取多个对象
若一个网页包含基本 HTML 和 个引用对象,非持续连接逐个获取、不并行,且每次 RTT 均为 ,各对象大小为 ,则
HTML 加 10 张图片共有 11 个对象,连接与请求开销约为 。浏览器若并行建立连接,时间线会改变,不能继续直接套用这个顺序模型。
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 版本 |
观察方法:手工发送 HTTP 请求
连接一个提供明文 HTTP 服务的测试服务器的 TCP 80 端口后,发送请求行、
Host首部和末尾空行,就能观察响应状态、首部和消息体;也可以使用 Wireshark 查看交互。这一操作针对明文 HTTP,HTTPS 需要先完成 TLS 等过程,不能直接将相同文本发送到 443 端口就期待得到正常响应。