摘要

  • RFC 1055 将 SLIP 限定为串行线路上的 IP 数据报定界约定:END 结束一帧,ESC 保护会与结构字节冲突的两种数据值。
  • 建议在每帧开头增加一个 END,是为了把线路噪声可能遗留在接收端的字节冲掉;健康线路上多出的代价是一帧被忽略的空数据报。
  • 找到边界、确认内容完整、让依赖历史状态的解码器重新对齐,是不同任务。RFC 1144 与后来的 PPP 都使这种分工更清楚,而非把它归功于一个分隔符。

一份不假装包办一切的规范

RFC 1055 对 SLIP 的介绍很克制。1988 年的文本称它为点对点串行 TCP/IP 常用的事实约定,而不是 Internet Standard;它只是一个 packet framing protocol——为串行线上的 IP 包规定一段定界字符序列,“仅此而已”。

“仅此而已”不是缺点清单的开场白,而是一个责任边界。RFC 明说 SLIP 没有地址协商、没有包类型标识、没有错误检测或纠正,也没有压缩。两端必须在别处知道对方的 IP 地址;一条线也不能靠 SLIP 的类型字段同时辨认 TCP/IP 和别的网络协议,因为它根本没有该字段。一个被损坏的帧不会因为遇到结束字节就获得完整性证明。

若把这种早期格式理解成“尚未长成 PPP”,反而会错过其真正的工程选择。SLIP 所承担的最小共同工作是:面对连续到达的字节流,两个端点如何在本地、确定地同意一份 IP 数据报在哪里结束。为了让载荷中的某些值不被误读为回答这个问题,它还需要一个有限的转义规则。它并不借此取得对地址、可靠性、身份或上层语义的控制权。

RFC 1055 为这一工作保留两个八位组:END 为八进制 0300、十进制 192,ESC 为八进制 0333、十进制 219。数据中若出现 END,发送方改发 ESC 加八进制 0334;若出现 ESC,则改发 ESC 加八进制 0335。所有受保护的载荷字节发送完毕后,发送方发出 END;接收方在相同语法内逆转这两种替换。

这不是泛泛的“字符转义”。END 只在一个已经进入 SLIP 读帧状态的接收方那里拥有结构意义。ESC 只引入两个约定替换。发送方留下足以让本层读者还原的局部痕迹,接收方也只撤销那一层所认可的痕迹。这个机制阻止载荷篡夺外层定界语法,却不判断载荷本身是否正确。

在下一帧之前先结束一次

RFC 1055 中最值得细读的部分来自 Phil Karn 的建议:包不仅以 END 结尾,也以 END 开头。文本给出的理由非常具体——先发送的 END 可以清除因线路噪声而积存在接收器中的错误数据。

在线路正常时,这一动作看起来像重复。上一个包的结尾 END 与下一个包的开头 END 相邻出现。RFC 不把它隐藏成例外:它们会形成一个空的或错误的 IP 包;IP 实现会丢弃它,而文中给出的接收例程在尚未收集任何数据时遇到 END,直接忽略。一个可丢弃的空帧,正是为边界保险支付的明确成本。

在线路受扰时,同一个字节承担的不是“验证”而是“切断”。接收缓冲区里可能有若干字节,它们既不能被可靠地归属为旧包,也不应被允许充当新包的前缀。前置 END 终止这段不明积累。噪声留下的内容被舍弃,而后续有效载荷开始抵达时,接收方已经回到一个清晰状态:等待一帧边界之后的数据。

所以,把这个字节说成“恢复了数据包”并不准确。它恢复的是阅读起点:先前不确定的字节不再有资格规定下一次解释的开头。它没有修复被丢弃的字节;没有证明新包没有比特错误;也没有获知上层的有状态解码器是否和发送方记住了同一段历史。

RFC 的接收代码正好为这种克制提供了证据。它仅在 END 到来且已接收数据时返回一个包;相邻 END 形成的零长度情况被跳过。看到 ESC 后,它只认识两种规定的后继值;若后继不是其中之一,示例称之为协议违规,并把该字节原样存入缓冲区。这里没有全面的有效性裁判,只有一个小型边界读取器,以及保护两个结构字节不落入歧义的规则。

帧能重新找到,状态未必能回来

RFC 1144 关于低速串行链路 TCP/IP 头部压缩的写法,让这种区分变得格外重要。它的处理链把 IP 包先交给 compressor,再交给 framer。压缩器会为串行线路上的连接保存先前头部;压缩包可能只描述相对那份历史发生了什么变化。

因此,“已经分出一帧”并不等于“已经拥有解读它所需的状态”。接收端可以正确看到一个 END,截取一段字节,却没有证据表明该段字节未损坏;即使帧未损坏,解压器仍可能缺少发送方假定存在的前序状态。RFC 1144 把错误检测置于 framing 层,并指出解压器需要得到错误指示,才能丢弃坏包而不让错误继续传播。SLIP 的前置 END 不提供那个指示,它也从未宣称提供。

这里至少有三项彼此独立的事实:边界在哪里;边界内的八位组是否完整;有状态的消费者是否与对端处于相容的历史。分隔符回答第一项。校验、FCS 或其他错误检测可能回答第二项。重置、显式同步或上层协议的规则才可能处理第三项。把三者合成“恢复成功”,就是让一个没有相应观察能力的字节承担了不属于它的责任。

RFC 1662 提供的是后来的窄对照,而不是历史审判。PPP 的 HDLC-like framing 规定了可标示帧首或帧尾的 flag、八位组填充、FCS 和无效帧处理。它还提醒:把一个 flag 同时用作前帧结尾和后帧开头,能省一个八位组、降低延迟,却可能在空闲后的噪声条件下损失可靠性;没有新的开旗标时,垃圾字符可能被拼进下一帧。两份文档都承认边界与重同步的价值,但 PPP 把它放在一个更广、且明示完整性规则的链路契约之中。

让标记的权力在边界处到期

Heng Lu 的 Note 64 和 Note 65 提供了一种适合此处的阅读纪律:从运行实现可在本地验证的最小确定性功能出发,不把它扩展为无边界的权力。SLIP 中的 END 有效到恢复读帧边界为止;ESC 的效力仅限于两种保留值。它们一旦完成定界,就不能证明随后字节安全,也不能替一个依赖历史的解码器恢复共同状态。

因此,分析一次流恢复时,应分别保留:标记前的原始缓冲内容、观察到的 END、其后组装的帧、独立的完整性结果,以及所有有状态消费者在此之前和之后使用的状态。日志若只写“已恢复包”,往往把本可以分别验证或否定的多个判断压成一行。

来源与证据边界

本文的封闭证据集为 RFC 1055、RFC 1144 与 RFC 1662。它们支持 END/ESC 语法、前置 END 的理由、SLIP 明示未提供的能力、压缩器与 framing 的分工,以及与 PPP 的有限对照。它们不证明 SLIP 的普遍部署、任何现代设备的行为、可量化的噪声发生率、安全结论,或每条 SLIP 线路都使用 RFC 1144。