PPP 协议:封装成帧与透明传输#
视频讲解:#
https://www.bilibili.com/video/BV1G2pr6aEsh/(嗒特老师)
一句话讲清#
数据链路层把网络层交下来的 IP 数据报装进「帧」:前后加首部和尾部,尾部带 CRC 校验码,首尾各一个标志字段负责定界。如果数据里恰好出现了跟标志一样的字节,就用填充法把边界藏起来——这就是透明传输。PPP 有两条路:
- 异步传输 → 字节填充(转义字符
0x7D) - 同步传输 → 零比特填充(5 个连续 1 后面插一个 0)
一、封装成帧:把数据报装进信封#
数据链路层以帧为单位传输和处理数据。网络层的 IP 数据报向下交给数据链路层,成为帧的数据部分,在它前面和后面分别加上首部和尾部,封装成一个完整的帧。
- 帧长 = 数据部分长度 + 首部长度 + 尾部长度
- 接收方必须能正确识别每个帧的开始和结束——这叫帧定界
- 首部和尾部的重要作用之一就是帧定界,同时携带必要的控制信息
- 数据部分的长度有上限,即最大传送单元 MTU
为什么非定界不可?因为物理层只认一串连续的比特流,它不知道哪里是帧的头、哪里是尾。帧的边界是数据链路层自己加出来的。
二、PPP 帧长什么样#
| 字段 | 长度 | 取值 / 含义 |
|---|---|---|
| 标志字段 F | 1 字节 | 0x7E(二进制 01111110)——帧的定界符 |
| 地址字段 A | 1 字节 | 固定 0xFF(实际不起作用) |
| 控制字段 C | 1 字节 | 固定 0x03(实际不起作用) |
| 协议字段 | 2 字节 | 0x0021 表示信息字段就是 IP 数据报 |
| 信息字段 | 可变 | 载荷,长度 ≤ 1500 字节 |
| 帧检验序列 FCS | 2 字节 | 用 CRC 算出的检错码 |
| 标志字段 F | 1 字节 | 0x7E,与首部标志相同 |
- PPP 面向字节,所有 PPP 帧的长度都是整数个字节
- 帧首和帧尾的标志字段相同;连续两个帧之间只需要一个标志字段
三、透明传输:数据"撞上"定界符怎么办#
目标是「透明传输」:数据链路层对上层交下来的数据不挑食——不管里面是什么内容,都能原样传过去,就好像数据链路层不存在一样。
冲突点:标志字段 0x7E 是用来定界的。如果信息字段里恰好也出现了 0x7E,接收方会误以为帧到此结束:
- 前面那一段被当成一个「完整的帧」收下
- 后面剩下的数据因为找不到结束标志,被丢弃
解决办法:按链路的传输方式分两套。
3.1 异步传输 → 字节填充(转义字符 0x7D)#
RFC 1662 规定的填充方法:
| # | 信息字段中出现 | 发送端变换为 | 规律 |
|---|---|---|---|
| 1 | 0x7E |
0x7D 0x5E |
前面插转义符,字符异或 0x20 |
| 2 | 0x7D |
0x7D 0x5D |
转义符自己也要转义 |
| 3 | 小于 0x20 的 ASCII 控制字符 |
0x7D + 编码改变 |
例如 0x03 → 0x7D 0x23 |
- 规律:异或
0x20。0x7E ^ 0x20 = 0x5E,0x7D ^ 0x20 = 0x5D,0x03 ^ 0x20 = 0x23 - 发送端填充后,链路上传送的字节数比原来的信息字节数多
- 接收端做相反的变换,就能正确恢复出原来的信息
3.2 同步传输 → 零比特填充#
同步传输是一连串比特连续传送(面向比特),帧长不必是整数个字节,可以用开销更小的零比特填充:
- 发送端:扫描整个信息字段,只要发现有 5 个连续 1,就立即填入一个 0
→ 保证信息字段里永远不会出现 6 个连续 1,也就不会和标志
01111110撞车 - 接收端:先找到标志字段
01111110确定帧的边界,再扫描比特流,每当发现 5 个连续 1,就把后面那个 0 删掉,还原成原来的数据 - 通常用硬件实现,处理快
四、两种方式对比#
| 异步传输 | 同步传输 | |
|---|---|---|
| 链路单位 | 字节 | 连续的比特流 |
| 定界标志 | 0x7E |
01111110 |
| 透明传输方法 | 字节填充 | 零比特填充 |
| 具体规则 | 转义字符 0x7D;0x7E→7D 5E,0x7D→7D 5D,<0x20 前置 0x7D 并异或 0x20 |
5 个连续 1 后插 1 个 0 |
| 实现 | 软件 / 字节处理 | 硬件,开销更小 |
五、易错点#
0x7E的二进制是01111110——中间有 6 个连续 1,这就是"5 个 1 后插 0"能防冲突的原因。- 转义符
0x7D本身也要转义:数据里出现0x7D→ 变成0x7D 0x5D(别漏)。 - 小于
0x20的控制字符不是简单加个0x7D,而是加0x7D且改变编码(异或0x20)。 - 零比特填充是"5 个连续 1 后插 0",不是 6 个。
- 字节填充会让链路上传的字节数变多,但接收端还原后和原始数据完全一致。