
上一篇我们介绍了计算机网络的分层模型。分层以后,每一层都有自己负责的功能,也会给上层的数据加上一些控制信息。
所以,同一份用户数据在不同层中会有不同的名字,他们分别是:报文、数据段、数据报、帧、比特流
这些名字是为了在说明:数据当前已经被哪一层处理过,以及接下来由谁负责传输。
为什么同一份数据有这么多名字?
我们在浏览器中输入一个网址,最终发送出去的并不是一段孤零零的 HTTP 文本。
例如浏览器准备发送下面这个请求:
GET / HTTP/1.1
Host: www.baidu.com
浏览器只关心“我要请求什么资源”,但网络要解决的问题更多:
- 这份数据应该交给哪个应用进程;
- 数据是否可靠到达,丢失后怎么办;
- 目标主机在互联网中的 IP 地址是什么;
- 当前这一跳应该交给哪一块网卡;
- 最后怎样把数据变成网线、光纤或无线信号中的 0 和 1。
这些问题分别由不同层解决。因此数据每向下一层传递一次,都会附加该层需要的控制信息,数据的称呼也会随之变化。
五层模型中的数据形态
在我们使用的五层参考模型中,各层对应的数据单位如下:
| 应用层 | 为用户应用提供网络服务 | 报文 |
| 运输层 | 进程到进程的通信、可靠传输等 | TCP 报文段 / UDP 用户数据报 |
| 网络层 | 主机到主机的传输与路由选择 | IP 数据报,也常称为分组 |
| 数据链路层 | 在一段链路上把数据交给下一跳 | 帧 |
| 物理层 | 在传输介质上发送信号 | 比特流 |
这里有两个容易混淆的地方:
- 报文有时是一个比较宽泛的说法,泛指网络中传输的一段消息。在五层模型的语境中,通常把应用层交给运输层的数据称为应用层报文。
- 运输层要区分协议。TCP 对应的是报文段,UDP 对应的是用户数据报。初学阶段,我们也常把它们统称为运输层数据。
数据向下传递:封装过程
数据从应用层向物理层传递的过程称为封装。
每一层收到上层交下来的数据后,都会把它看作自己的数据部分,然后添加本层的协议控制信息,组成新的协议数据单元。
HTTP 请求报文
-> TCP 首部 + HTTP 报文 = TCP 报文段
-> IP 首部 + TCP 报文段 = IP 数据报
-> 帧首部 + IP 数据报 + 帧尾部 = 以太网帧
-> 比特流 / 电信号 / 光信号 / 无线信号
1. 应用层:报文
应用层直接面向用户程序。
浏览器生成的 HTTP 请求、DNS 查询消息、电子邮件内容等,都可以看作应用层报文。应用层关心的是业务语义,例如“请求网页”“查询域名”“发送邮件”。
它并不需要知道底层具体经过了哪些路由器,也不需要关心网线中的电信号长什么样。
2. 运输层:数据段
运输层收到应用层报文后,会添加运输层首部。
如果使用 TCP,形成的是 TCP 报文段。TCP 首部中包含源端口号、目的端口号、序号、确认号等信息,用于实现可靠传输、流量控制和拥塞控制。
如果使用 UDP,形成的是 UDP 用户数据报。UDP 的首部更简单,主要包含端口号、长度和校验和等信息。
端口号的作用是区分主机上的不同应用进程。比如浏览器访问 Web 服务时,目的端口通常是 80 或 443。
3. 网络层:数据报
网络层收到 TCP 报文段或 UDP 用户数据报后,会添加 IP 首部,形成 IP 数据报。
IP 首部中最关键的信息是源 IP 地址和目的 IP 地址。路由器正是根据目的 IP 地址,为数据报选择下一跳,从而让数据能够跨越不同网络到达目标主机。
网络层只负责让数据报尽力到达目标主机,并不保证一定送达。是否需要可靠传输,通常由上面的 TCP 来完成。
4. 数据链路层:帧
IP 数据报还不能直接在以太网或 Wi-Fi 中传输。数据链路层会在 IP 数据报前后增加控制信息,形成 帧。
以太网帧中通常会包含:
- 帧首部:源 MAC 地址、目的 MAC 地址、类型等;
- 数据部分:上层交下来的 IP 数据报;
- 帧尾部:帧校验序列 FCS,用于检测传输过程中是否出现比特错误。
需要注意的是,MAC 地址解决的是当前链路中的下一跳交付问题。
例如,电脑访问互联网上的 Web 服务器时,电脑通过 ARP 查询到的通常是默认网关的 MAC 地址,而不是远端 Web 服务器的 MAC 地址。数据先被封装成“发给默认网关”的帧,再由路由器继续转发。
5. 物理层:比特流
帧到达物理层后,会被转换成可以在介质中传播的比特流。
在网线中,0 和 1 会表现为不同的电信号;在光纤中,会表现为不同的光信号;在 Wi-Fi 中,则会表现为无线电波信号。
物理层并不理解 HTTP、TCP 或 IP,它只负责把比特可靠地送到物理链路的另一端。
用一次 HTTP 请求串起来
假设我们访问 http://www.baidu.com/,并且已经通过 DNS 得到了服务器的 IP 地址。
浏览器生成 HTTP 请求后,数据大致会经历下面的过程:
从浏览器的角度看,它发送的是 HTTP 请求;从网卡的角度看,它发送的是一串比特;从路由器的角度看,它主要处理的是 IP 数据报和当前链路上的帧。
这就是分层带来的视角差异:同一份数据,在不同层看来是不同的对象。
数据到达服务器:解封装过程
服务器收到数据后,会按照相反的方向处理,这个过程称为解封装。
比特流
-> 识别出以太网帧,去掉帧首部和帧尾部
-> 得到 IP 数据报,去掉 IP 首部
-> 得到 TCP 报文段,去掉 TCP 首部
-> 得到 HTTP 请求报文,交给 Web 服务器程序
在实际处理时,每层都会先检查本层首部中的信息:
- 数据链路层检查目的 MAC 地址和帧校验;
- 网络层检查目的 IP 地址,并判断该数据报是否应交给本机;
- 运输层根据目的端口号,把数据交给对应的应用进程;
- 应用层的 Web 服务器最终读取 HTTP 请求,并返回 HTTP 响应。
响应从服务器返回客户端时,同样会经历一次封装、传输和解封装,只是源地址和目的地址的角色相反。
可以参考这个图理解:

经过路由器时,什么会变?
很多人刚接触封装时会有一个疑问:数据经过很多路由器,是不是每一层都会被拆开再重新封装?
通常不是。
路由器主要工作在网络层,同时也需要处理它连接的两端数据链路层。一个帧到达路由器后,大致会发生下面的事情:
可以参考下图理解:

再理解 PDU、SDU 与 PCI
上一篇提到过三个概念:PDU、SDU 和 PCI。它们正好可以用来解释封装。
- SDU(服务数据单元):上层交给本层的数据;
- PCI(协议控制信息):本层为了实现协议而添加的控制信息,通常就是首部,有时还包括尾部;
- PDU(协议数据单元):本层最终形成的数据单位。
它们之间的关系是:
本层 PCI + 本层 SDU = 本层 PDU
例如,TCP 把 HTTP 报文作为自己的 SDU,加上 TCP 首部后形成 TCP 报文段;这个 TCP 报文段又会成为 IP 层的 SDU。
也就是说,上层的 PDU,就是下层的 SDU。
可以参考这个图理解:

小结
从应用程序发出请求,到数据真正进入网络,数据会依次经历下面几种形态:
应用层:报文
运输层:TCP 报文段 / UDP 用户数据报
网络层:IP 数据报(分组)
数据链路层:帧
物理层:比特流
向下传递时,每层添加自己的控制信息,这叫封装;到达接收方后,数据逐层去掉控制信息并交给上层,这叫解封装。
理解这条链路后,后面学习 TCP、IP、以太网、路由器转发时,就不会只看到一堆零散的首部字段,而能知道它们分别处在什么位置、解决什么问题。
下一篇我们继续看:互联网中的数据为什么通常被拆成一个个分组来传输,以及分组交换和电路交换有什么区别。
如果这篇文章对你有帮助,欢迎点赞、评论、关注、收藏。你们的支持是我前进的动力!
