RFC 5 带读:Decode Encode Language (DEL)——1969 年的可下载前端程序与跨终端交互
前言
读完 RFC 1~4,再打开 RFC 5,会突然发现画风变了。
前几篇还在讨论 Host Software、IMP、Link、网络联调和 RFC 文档制度,RFC 5 却直接拿出了一门编程语言:
DEL(Decode-Encode Language,解码-编码语言)。
而且这不是一份只有几页的概念提案。RFC 5 从网络交互模型一路写到语言语法,里面有:
- Function、Procedure、Co-routine;
- Integer、Real、Tree、Pointer、Buffer;
IF、WHILE、FOR、CASE、GO TO;- Message 的构建、发送和接收;
- Display Buffer;
- Vector、Beam Position、Intensity、Blink、Italics;
- Wand、Joystick、Keyboard、Buttons、Light Pen,甚至 Mouse。
如果只把它当作“一门没流行起来的古老语言”,就会错过 RFC 5 真正有意思的部分。
DEL 想解决的核心问题其实是:
当用户通过一个慢速网络,使用本地完全不同的计算机和终端,去操作远端交互式系统时,怎样避免每一次按键、显示变化和设备差异都必须由远端主机处理?
它给出的答案非常大胆:
1 | |
也就是说,RFC 5 试图把一部分远程应用的前端逻辑下沉到用户所在的计算机执行。
这不是 JavaScript,也不是 Java Applet,更不是现代 Edge Computing 的直接祖先,但其思想与今天很多系统非常容易产生共鸣:
1 | |
这种相似并不是后人硬凑出来的。
Steve Crocker 在 1999 年的 RFC 2555《30 Years of RFCs》 中回顾这段历史时,明确提到他们当时想在会话开始时下载一个小程序,由它控制交互并更有效地使用窄带网络;他把 DEL 看作这一思路的早期尝试,并在回顾中把 Java、ActiveX 与这种早期设想联系起来。
2019 年的 RFC 8700《Fifty Years of RFCs》 又进一步概括:早期 Network Working Group 曾设想 application-specific protocols(应用特定协议),并把代码下载到用户站点,DEL 是最初版本,后来又发展出 NIL(Network Interchange Language)。
所以 RFC 5 最值得带读的,不是每一个古老语法符号。
真正值得理解的是:
1969 年,网络还没正式投入使用时,人们已经在思考“远端应用、可下载代码、本地运行时、统一设备抽象、本地即时反馈和语义化显示”应该怎样组合起来。
RFC 基本信息
| 项目 | 内容 |
|---|---|
| RFC | RFC 5 |
| 官方英文标题 | Decode Encode Language (DEL) |
| 作者 | Jeff Rulifson(J. Rulifson) |
| 所属机构 | SRI(Stanford Research Institute) |
| 工作组 | Network Working Group |
| 文档日期 | June 2, 1969 |
| RFC Editor 当前发布日期 | June 1969 |
| RFC Editor 当前状态 | Unknown |
| Stream | Legacy |
| 早期 NIC 文档号 | 4691 |
| RFC Editor 信息页 | RFC 5: Decode Encode Language (DEL) |
| RFC 原文 | RFC 5 原文 |
RFC 5 原文页眉中的年份曾显示为:
1 | |
这里的 l 是 OCR 把数字 1 识别成了字母 l。RFC Editor 已有 Verified Editorial Erratum 将其确认应为:
1 | |
RFC 5 是“工作文档”,不是定稿语言标准
RFC 5 在摘要之后直接声明:
这是用于 DEL 语言演化的 working document。
所以阅读时必须注意:
1 | |
原文中到处保留着这种“设计还在现场发生”的痕迹,例如:
1 | |
以及:
1 | |
甚至在讨论 program composition 时直接留下一句:
1 | |
这不是后人整理好的标准,而是一份真实的设计工作稿。
RFC 5 没有被 RFC Editor 标成“Obsoleted by RFC X”
这一点与 RFC 3、RFC 4 不同。
RFC Editor 当前没有给 RFC 5 标出一个直接的:
1 | |
而 1971 年的 RFC 100《Categorization and Guide to NWG/RFCs》 甚至把 RFC 5 放入:
1 | |
并用 * 标记在当时的 current issues 子集中。
因此不能简单写成:
1 | |
更准确的历史关系是:
1 | |
后来 ARPANET 实际协议体系并没有把 DEL 作为通用网络执行环境部署下来,但它属于一条持续了一段时间的研究路线。
为什么会有这篇 RFC
一、最初的 ARPANET 首先面对的是“远程交互”
RFC 5 的 Foreword 记录了一个很重要的时间点:
1 | |
最初的 ARPA Network Working Group 在 SRI 开会。
参会者包括:
- Andrews;
- Baray;
- Carr;
- Crocker;
- Rulifson;
- Stoughton。
文档说,在开会之前,大家大体已经认同:
通过网络运行 interactive programs(交互式程序),会是最先遇到的问题之一。
这和今天想象“计算机联网”时很不一样。
今天我们第一反应可能是:
1 | |
但 1968~1969 年的核心场景之一是:
1 | |
换句话说,他们很早就在面对:
Remote Interactive Computing(远程交互式计算)。
二、50 Kbit/s 在当时已经让他们担心交互体验
Steve Crocker 在 RFC 2555 回忆,当时 ARPANET 使用的通信线路大约是:
1 | |
他们担心这个带宽不足以提供高质量的交互式体验。
但 DEL 面对的问题不仅是纯吞吐量。
真正棘手的是:
1 | |
如果每一个字符、按钮、光笔动作、鼠标动作都必须如此处理,那么:
- 网络 RTT 会进入用户交互关键路径;
- 远端 TSS 会频繁被激活;
- 本地 TSS 也可能承担额外负载;
- 不同终端的特殊能力很难利用;
- 显示系统需要传输大量低层绘图数据。
RFC 5 明确指出,对于大型 display-oriented systems,如果每次按钮状态变化都必须激活 TSS 中的用户程序,通过网络运行时甚至会同时给两个系统造成不必要负担。
三、问题不仅是“慢”,还有终端完全不一样
早期网络并不是:
1 | |
大家都实现一个近似统一的 Web Platform。
而是不同站点有完全不同的:
1 | |
因此如果 Utah 的终端要访问 SRI 的 NLS,问题不是简单地:
1 | |
因为:
1 | |
更麻烦的是显示。
假设服务端想表达:
1 | |
不同终端的:
- 分辨率;
- 坐标系统;
- 向量能力;
- 存储管能力;
- 字符宽度;
- 强度;
- 闪烁;
可能完全不同。
如果服务端直接输出某台设备的硬件命令,就无法跨站点工作。
四、直接为每一对机器写转换器,会迅速失控
假设网络中有 N 种不同的交互环境。
最笨的方式是:
1 | |
概念上会趋向:
1 | |
种两两适配关系。
RFC 5 的目标之一就是减少这种 pairwise translation(两两转换)。
它提出一个中间的:
Universal Hardware Representation(通用硬件表示)。
思路变成:
1 | |
这样每个站点主要负责:
1 | |
每个服务系统负责:
1 | |
从架构上看,这比 N×N 的硬编码转换更容易扩展。
这里的 O(N²) 与 O(N) 是站在今天对其设计动机做的抽象,不是 RFC 5 原文给出的复杂度公式;原文明确说的目标是:
minimize the number of translators needed。
五、为什么不是传一个固定协议,而是“传程序”
如果所有应用都只需要 TTY,那么可以设计一套固定字符协议。
但 RFC 5 设想的范围更大:
1 | |
复杂交互系统的即时反馈规则可能完全不同。
所以它没有试图把所有应用行为都写死在一个巨大通用协议里,而是提出:
由服务端把针对该 subsystem 的 DEL 程序以 symbolic form(符号形式)发送到用户站点,再由用户站点本地编译。
这就是 RFC 5 最核心的思想。
核心内容
RFC 5 可以从五层理解:
1 | |
整体架构可以先画成:
flowchart LR
UI[本地交互设备<br/>Keyboard / Mouse / Light Pen / Display]
UHR[Universal Hardware Representation]
ENC[DEL Encode Program<br/>本地编译]
NSTU[NST Runtime / Library<br/>User Host]
NET[ARPANET / IMP Network]
DECODE[DEL Decode Program]
NSTS[NST / Host-side Support]
APP[Server-host Subsystem<br/>例如 NLS]
UI --> UHR
UHR --> ENC
ENC --> NSTU
NSTU --> NET
NET --> NSTS
NSTS --> APP
APP --> DECODE
DECODE --> NET
NET --> NSTU
NSTU --> UHR
UHR --> UI
这张图是根据 RFC 5 的文字结构重构的,不是原文正式架构图。
一、DEL 的两个基本任务
RFC 5 摘要把 DEL 的任务定义得非常清楚。
任务 1:用户 → 网络
接受 interactive console 的输入码:
1 | |
然后:
1 | |
任务 2:网络 → 用户
从另一台计算机接收 Message:
1 | |
然后:
1 | |
这两项任务直接对应:
1 | |
所以语言叫:
1 | |
二、NST:Network Standard Translator
RFC 5 把 **NST(Network Standard Translator)**描述为一组公共程序库。
它的职责是:
与用户站点从 DEL 程序编译出来的代码有效配合。
可以把它理解成一种:
1 | |
但不要直接把它等同于 JVM、浏览器 Runtime 或现代 VM。
RFC 5 的设计更像:
1 | |
三、NST-DEL 支持三个复杂度层次
RFC 5 特意强调,这套模型不是只为复杂图形系统服务,而是可以从简单模式逐级升级。
Level 1:几乎不转换
最低层模式中,信息直接以用户程序平时在 user-host 中接收的形式发送给 server-host。
这时 NST 基本:
1 | |
DEL 程序主要只是:
1 | |
也就是说,如果两边足够兼容,就不要为了“统一架构”强行增加转换。
Level 2:TTY + Echo Table
中间层用于普通 TTY。
DEL 程序在 user-host 上:
1 | |
服务端返回时:
1 | |
流程可以画成:
sequenceDiagram
participant U as User TTY
participant D as Local DEL/NST
participant N as Network
participant S as Server Host
U->>D: 输入字符
D-->>U: Immediate Echo
D->>D: Character Translation / Buffer
Note over D: Break 条件满足时
D->>N: Packed Message
N->>S: Server-format Input
S-->>N: Response
N-->>D: Server-format Output
D->>D: Translate to Local Character Set
D-->>U: Print / Display
Level 3:大型图形交互系统
最激进的模式用于复杂 display-oriented systems。
这时本地 DEL 程序不只是做字符回显,而会处理:
1 | |
大量“立即反馈”在本地完成。
只有达到某些重要交互点时,才向 server-host 发 Message。
架构变成:
1 | |
这就是 DEL 最核心的性能思想:
把高频、低价值、延迟敏感的交互留在本地;把真正需要远端计算的部分交给服务端。
四、Universal Hardware Representation:给不同设备找一个公共语言
RFC 5 为了减少设备之间的转换器数量,提出:
Universal Hardware Representation(UHR,通用硬件表示)。
它不是一套真实统一硬件,而是:
一种用于统一描述初始网络中各种交互式显示站硬件的抽象表示。
最直观的例子是屏幕坐标。
RFC 5 不要求统一真实像素分辨率,而是假定屏幕是一个正方形:
1 | |
可以表示为:
1 | |
于是一个点不再依赖:
1 | |
而是用归一化坐标描述。
这其实是一种非常经典的抽象思路:
1 | |
五、Logical Screen 比“像素流”更重要
在 DEL 的显示语义里,RFC 5 不只定义坐标。
它还提出:
1 | |
其中:
x、y表示位置;r表示相对 x 轴逆时针旋转的弧度。
Intensity 则归一化到:
1 | |
另外还有:
- character frame size;
- blink bit;
- italics;
- vector;
- beam position。
RFC 5 最值得注意的一句话是:
如果要画一条横跨屏幕的直线,就应该传输“这是一条直线”这个事实,而不是传 500 个短向量。
这说明作者希望网络上传输的是:
1 | |
而不是:
1 | |
抽象一下就是:
1 | |
而不是:
1 | |
这种思想与现代:
- Vector Graphics;
- Scene Graph;
- Declarative UI;
- Remote Rendering Protocol;
在抽象层上很相似。
但不能写成“SVG 或 React 直接源自 RFC 5”。RFC 5 只是在面对同一个基本问题:
网络上到底应该传设备细节,还是传更稳定的语义?
六、输入设备抽象非常超前
RFC 5 的 LOGICAL INPUT DEVICES 直接列出:
1 | |
注意这里有:
Mice。
这不是说 RFC 5 定义了现代鼠标网络协议。
它说明 DEL 从一开始就不是只为:
1 | |
设计的。
它试图覆盖一种更一般的:
1 | |
交互模型。
关键机制与工作流程
一、核心机制:服务端把“适配程序”发给用户端
RFC 5 用 NLS 举了一个非常具体的例子。
假设 Utah 的用户想使用 SRI 的 NLS。
流程是:
sequenceDiagram
participant U as Utah User
participant UH as Utah User-Host
participant S as SRI NLS / Server Host
U->>UH: 请求进入 NLS
UH->>S: 请求 NLS 所需 symbolic program
S-->>UH: DEL Remote Encode Program (REP)
UH->>UH: Compile REP for local machine
UH->>UH: Load with NST standard library
U->>UH: Keyboard / Mouse / Console Input
UH->>UH: Local Translation + Immediate Feedback
UH->>S: 只发送需要远端处理的 Message
S-->>UH: Logical / Display Response
UH-->>U: 转换为本地设备输出
RFC 5 把这个 DEL 程序称为:
NLS Remote Encode Program(REP)。
REP:
1 | |
当程序第一次到达 Utah:
1 | |
这个细节非常重要:
RFC 5 不是要求服务端为每一种远端机器预编译一份二进制程序,而是传输符号程序,让接收站点根据自己的机器进行编译。
二、为什么传 Symbolic Program,而不是 Machine Code
RFC 5 明确列出这种方式的优势。
每个站点可以:
1 | |
因此本地编译器可以针对:
- 本机字长;
- 指令集;
- 终端硬件;
- 特殊按钮;
- 本地 Monitor;
生成更合适的 Machine Code。
原文期待得到:
1 | |
也就是说:
1 | |
这是一种非常有意思的 portability 策略。
三、服务端升级后,远端前端也可以随之更新
RFC 5 还强调:
如果 host-site 的系统增加新功能,host programmer 只需要更新:
1 | |
用户站点下次收到并编译新程序以后,新功能就会随之进入远程访问环境。
即:
1 | |
这已经有非常明显的:
1 | |
味道。
它解决的不是单纯“数据格式升级”,而是:
应用交互逻辑如何与服务端版本一起演进。
四、本地站点仍然可以插入自己的扩展
RFC 5 并不希望远端下发的程序完全控制本地终端。
原文说,user-site programmer 可以在本地 Monitor System 和 host 下发的 DEL program 之间插入额外 symbolic programs。
用途包括适配:
1 | |
所以整体不是:
1 | |
而更像:
1 | |
这也是 DEL 试图解决“非标准终端模拟另一种非标准终端”的方法。
五、User-to-Host 数据流
RFC 5 对用户到服务端的数据路径写得很细。
可以重构成:
flowchart LR
DEV[Keyboard / Buttons / Mouse<br/>Local Devices]
MON[Monitor / Interrupt Handlers]
ENC[Encode Translator<br/>DEL]
FB[Local Display Management<br/>Immediate Feedback]
MSG[Message Packing]
IMP1[User-site IMP]
NET[ARPANET]
IMP2[Server-site IMP]
HRT[Host Reception Program]
APP[Server Subsystem]
DEV --> MON --> ENC
ENC --> FB
ENC --> MSG --> IMP1 --> NET --> IMP2 --> HRT --> APP
Encode Translator 可以做:
1 | |
所以它不是一个简单的 charset.convert()。
它是:
输入流状态机 + 本地反馈逻辑 + 协议编码器。
六、Host-to-User 数据流
反方向更复杂。
服务端输出首先进入:
1 | |
它将输出转换成简化的:
1 | |
然后经过网络,在用户端继续由:
1 | |
处理。
可以画成:
flowchart LR
APP[Server Subsystem]
DEC[Decode Translator]
LOGIC[Logical Entity Stream]
NET[ARPANET / IMP]
URT[User Reception Translator]
DCTRL[Display Control]
PCTRL[Program Control]
DISPLAY[Local Display]
SUBSYS[Local Subsystem / Storage]
APP --> DEC --> LOGIC --> NET --> URT
URT --> DCTRL --> DISPLAY
URT --> PCTRL --> SUBSYS
其中 Program Control 还可以把数据选择性地路由到本地其他 subsystem。
RFC 5 举例说:
1 | |
这说明 DEL 想处理的并不只是字符和图像,还有:
1 | |
七、本地显示为什么要保留“逻辑结构”
RFC 5 认为服务端输出应该尽量携带逻辑意义。
例如不同用户终端的行宽可能不同,所以不应该只发“已经排好版的物理字符位置”,而应该保留:
1 | |
同理:
1 | |
应该作为一个逻辑实体传输,而不是拆成大量微小向量。
原因是:
1 | |
这样实时显示操作的责任就可以:
1 | |
也就是向用户端下沉。
八、Co-routine:用于组织流式交互转换
RFC 5 Foreword 记录:
1 | |
的一次讨论导致 DEL 加入了正式的:
Co-routines(协程)。
RFC 5 的语法里,Function、Procedure 和 Co-routine 被明确区分。
其中:
1 | |
语言还定义:
1 | |
可以把这种机制抽象理解为:
flowchart LR
A[Coroutine A]
P[PIPE]
B[Coroutine B]
A -->|STUFF value IN pipe| P
P -->|FETCH pipe| B
它非常适合描述:
1 | |
这种多阶段数据流。
不要把 RFC 5 的 Co-routine 直接等同于今天 Java/Kotlin/Go/async runtime 的协程实现;这里重要的是:
语言设计者已经需要一种比普通 Call/Return 更适合流式交互处理的控制结构。
九、DEL 的语言结构其实相当完整
虽然 RFC 5 是 Working Document,但其 Language 部分已经覆盖大量传统语言结构。
Procedure Model
支持:
1 | |
Data / Declaration
可见的类型与结构包括:
1 | |
Arithmetic
支持:
1 | |
Logic
支持:
1 | |
而且原文明确希望编译器对:
1 | |
跳过不必要的后半部分计算。
也就是今天熟悉的:
Short-Circuit Evaluation(短路求值)。
Flow Control
支持:
1 | |
十、Semi-Tree:显示数据并不是平铺 Buffer
DEL 还定义了:
1 | |
以及:
1 | |
用于构建和操作 Semi-Tree。
原文还明确说,额外括号可以像 LISP 一样产生线性子分类。
这说明 DEL 对复杂显示的设想不是简单:
1 | |
而更接近:
1 | |
十一、Message I/O 是语言一级能力
DEL 直接把网络 Message 构建写进语言语法。
原文包含类似:
1 | |
也就是说,DEL 不是一门与网络无关的通用语言再调用外部 Socket Library。
它是一门:
为网络交互与表示转换专门设计的 Domain-Specific / Special-purpose Language。
当然,当时还没有今天意义上的 Socket API。
十二、Display Buffer 同样是语言一级对象
DEL 提供:
1 | |
Buffer 中可以追加:
1 | |
显示参数包括:
1 | |
这让 DEL 同时具有:
1 | |
的特征。
重点概念与术语
DEL
DEL(Decode-Encode Language)。
一种面向网络交互、终端适配和显示转换的 machine-independent language 设想。
其核心用途不是普通业务计算,而是:
1 | |
NST
NST(Network Standard Translator)。
RFC 5 所设想的公共 Translator Library / Runtime。
每个节点实现 NST,再运行从 DEL symbolic program 编译出来的本地代码。
Universal Hardware Representation
Universal Hardware Representation(UHR)。
用于抽象不同站点交互硬件的公共逻辑表示。
典型例子:
1 | |
User-host
用户实际所在的 Host。
负责接收本地输入设备事件、运行本地 DEL/NST 逻辑、显示反馈并访问远端服务。
Server-host / Serving-host
运行被访问 subsystem 的远端 Host。
例如 RFC 5 示例中的 SRI NLS 所在系统。
NLS
NLS(oN-Line System)。
Douglas Engelbart 团队在 SRI 开发的交互式系统,也是最早期 ARPANET 远程交互实验的重要对象。
RFC 1 和 RFC 5 都反复使用它作为复杂网络交互案例。
REP
REP(Remote Encode Program)。
RFC 5 示例中的:
1 | |
由 NLS 提供,使用 DEL 描述,下载到远端用户 Host 并在那里编译运行。
原文稍后有一处写成 NLS NEP,文本本身存在这种不一致;阅读时不宜擅自把所有缩写静默“修正”为同一个名称。
Encode Translator
处理:
1 | |
同时可以承担:
- 字符转换;
- 字符聚合;
- Break 判断;
- Message Packing;
- Immediate Feedback。
Decode Translator
把 server-host 的输出转换为更通用、逻辑化的输出结构。
例如把:
1 | |
提升为:
1 | |
Immediate Feedback
即时反馈。
用户输入后无需等待远端 Host 往返即可生成的本地反馈。
这是 DEL 降低交互延迟和 TSS 负载的核心机制。
Break Character
用于决定什么时候应该把已经 Buffer 的字符真正发送到 server-host 的控制字符或条件。
DEL 在普通 TTY 模式中可以持续本地处理,直到遇到适当的 Break Character 才形成 Message。
TSS
TSS(Time-Sharing System,分时系统)。
RFC 5 担心复杂交互会因为每个按钮或输入事件反复激活用户程序,给本地和远端 TSS 都增加额外负担。
Symbolic Program
以符号形式传输的 DEL 程序,而不是某一种机器的原生 Machine Code。
接收端负责:
1 | |
Co-routine
DEL 的控制结构之一。
配合 PIPE、STUFF、FETCH 描述交互数据流和可恢复执行过程。
Semi-Tree
DEL 用来组织结构化显示信息的数据结构。
具有:
1 | |
等操作。
PREG
逻辑屏幕的位置寄存器:
1 | |
r 为逆时针旋转角,单位为 radians。
NIL
NIL(Network Interchange Language)。
DEL 后续的一条演化路线。
RFC 51 提出 NIL,引入更一般化的 Network Machine 抽象。
RFC 8700 直接把:
1 | |
描述为这条早期网络语言思想的前后版本。
需要特别注意的点
1. DEL 不是“1969 年的 JavaScript”
这类类比很吸引人,但容易写过头。
DEL 与现代浏览器脚本确实有相似点:
1 | |
Steve Crocker 后来也明确把这类早期想法与 Java、ActiveX 联系起来。
但技术谱系上不能写成:
1 | |
RFC 5 没有:
- DOM;
- Browser;
- HTTP;
- JavaScript Runtime;
- Web Security Model;
- Same-Origin Policy。
正确说法应该是:
DEL 是非常早期的 downloadable interaction code / mobile-code-like 架构尝试,后来出现的 Java、ActiveX 等让 Crocker 看到了相似思想的再次出现。
2. DEL 也不是现代 Thin Client 的简单翻版
普通 Thin Client 常把大量逻辑集中到 Server。
DEL 反而强调:
1 | |
所以它同时具有:
1 | |
两个方向。
3. “Machine Independent”并不意味着语义真的完全可移植
RFC 5 自称 DEL 是:
1 | |
但在 Arithmetic 部分又明确写:
1 | |
作者甚至警告:
如果程序依赖 word length、two’s complement arithmetic 等机器细节,最终会遇到问题。
这是一个非常有意思的矛盾:
1 | |
今天依然如此。
例如:
- integer overflow;
- endianness;
- floating point;
- undefined behavior;
- native ABI;
都可能让“跨平台源码”在不同机器上产生不同结果。
4. UHR 是抽象设备,不是网络硬件标准
Universal Hardware Representation 很容易被误解成:
1 | |
实际上恰好相反。
它的目的就是:
1 | |
5. -1..+1 坐标不是现代 NDC 的直接来源
今天图形学中也存在 normalized device coordinates。
RFC 5 的归一化屏幕与现代 NDC 在思想上非常相似,但没有证据表明今天的图形 API 是从 RFC 5 直接继承这套坐标系统。
应把它理解为:
面对跨显示硬件适配问题时,自然产生的一种归一化抽象。
6. 原文中很多 Syntax 本身就不稳定
RFC 5 有大量:
- 拼写错误;
- OCR 问题;
- 不完整语法;
??;- 未完成 Sample Program;
- 空的
AUDIO OUTPUT DEVICES小节。
因此不应该拿 RFC 5 当前机器可读文本直接实现一个“严格兼容 DEL Compiler”,然后声称这就是唯一正确语法。
它是 Working Document。
7. byte 在 RFC 5 中也不能默认等于今天的 8 bit octet
RFC 5 的语法甚至允许声明:
1 | |
早期计算机里的 byte 并没有今天“固定等于 8 bit”的普遍语义。
所以阅读老 RFC 时看到:
1 | |
都需要结合时代语境。
8. Source 中的 byute、message1 等文本不要强行现代化
当前文本中存在类似:
1 | |
这样的字符串。
这些可能来自原稿、转录或 OCR。
写带读博客时应该解释语义,而不是假装当前文本是一份现代 EBNF,可直接复制粘贴生成 Parser。
9. DEL 的安全模型几乎为空
这是站在今天看最严重的局限之一。
RFC 5 的核心操作是:
1 | |
但文档基本没有讨论:
1 | |
1969 年的研究网络环境与今天公开互联网的威胁模型完全不同。
如果今天重新设计这种系统,安全模型绝不能缺席。
10. Symbolic Download 的版本同步很漂亮,但也引入供应链问题
RFC 5 认为远端系统更新 DEL symbolic program 后,用户站点自动获得新功能是一个优势。
站在今天看,这同时意味着:
1 | |
现代系统必须进一步回答:
1 | |
11. RFC 5 不是后来 ARPANET 的通用应用协议
DEL 的想法没有成为所有 Host 必须实现的统一交互层。
RFC 8700 回顾说,在 BBN 给出 Host-IMP 硬件和软件接口规范后,Network Working Group 的注意力转向更底层的协议问题,早期“自动下载代码”的雄心一度消退。
因此不要把 DEL 放进这样一条错误栈:
1 | |
历史没有这样定型。
12. RFC 5 后续更准确的演化方向是 NIL 等 Network Language 研究
1971 年的 RFC 100 把:
1 | |
放在同一类问题下讨论。
这个问题是:
怎样让 user programs、data 和 network 之间进行可描述、可转换的适配。
所以 RFC 5 的影响不应该只从“编程语言史”看,还要从:
1 | |
这些方向看。
13. “直线而不是 500 个 Vector”是语义压缩,不只是带宽压缩
如果只是为了省带宽,可以简单压缩二进制。
RFC 5 更进一步:
1 | |
因为本地拥有语义以后,可以:
- 根据自己的显示器重新渲染;
- 适应不同分辨率;
- 进行本地操作;
- 避免绑定远端硬件表示。
这比单纯 gzip 一串设备命令更高级。
14. Immediate Feedback 不是最终业务结果
本地 DEL 可以立刻回显字符、更新显示、处理某些控制动作。
但这不代表 server-host 已经接受或执行相应业务操作。
必须区分:
1 | |
现代 optimistic UI 同样需要处理这种边界。
从今天的视角重新看这篇 RFC
一、它在解决“Local Fast Path vs Remote Slow Path”
RFC 5 最现代的地方,不是语法。
而是:
1 | |
DEL 的答案是:
1 | |
这个问题今天仍然出现在:
- Web 应用;
- 云游戏;
- Remote IDE;
- RDP/VNC;
- Edge Computing;
- Collaborative Editor;
- Mobile App;
- AI Agent UI。
网络快了很多,但:
1 | |
依旧通常比:
1 | |
便宜。
二、它很像 Code on Demand,但不是“下载任意可执行文件”
DEL 的关键策略是:
1 | |
如果用现代架构词汇描述,它很像:
1 | |
但其目标非常专用:
1 | |
而不是一门通用的应用分发平台。
三、NST 很像“公共 Runtime + App-specific Module”
RFC 5 要求每个 node 只实现一次 NST Library。
不同服务不再把所有底层适配代码重复一遍,而是只提供自己的 DEL program。
架构上可以抽象成:
1 | |
这种:
1 | |
模式今天依然非常常见。
四、UHR 在解决“中间表示”问题
两个异构系统之间转换,有两种典型策略。
方案 A:两两转换
1 | |
方案 B:公共中间表示
1 | |
RFC 5 的 Universal Hardware Representation 本质上选择了第二种。
今天同样的结构大量存在:
1 | |
它们并不是 DEL 的直接后代,但都利用了一个共同技巧:
不要让所有参与方互相理解;让所有参与方共同理解一个中间抽象。
五、服务器应该传“语义”,还是传“像素”
RFC 5 的直线例子非常值得今天重新看。
远程 UI 有两个极端:
Pixel / Device Streaming
1 | |
Semantic UI
1 | |
RFC 5 明显偏向第二种。
现代远程系统仍然在这两种策略之间做取舍:
1 | |
它们的差别最终还是:
1 | |
六、DEL 甚至碰到了 Optimistic / Immediate UI 的核心边界
用户按键后,本地先立即反馈:
1 | |
今天前端工程非常熟悉:
1 | |
当然 RFC 5 没有定义现代 optimistic transaction rollback。
但核心 UX 原理是一样的:
不要把所有感知延迟都暴露给用户。
七、把应用代码下放,会把性能问题变成安全问题
1969 年的设计重点是:
1 | |
今天如果做同样架构,第一个问题往往变成:
1 | |
于是必须出现:
1 | |
这是 DEL 与现代 Code-on-Demand 系统之间最重要的时代差异。
八、“本地编译”与今天 JIT / AOT / Wasm 的问题很像
RFC 5 选择 Symbolic Program,是为了:
1 | |
今天我们也会讨论:
1 | |
核心问题始终是:
1 | |
DEL 的答案属于 1969 年的硬件环境:
1 | |
九、它很早就暴露了“平台无关语言”的语义陷阱
RFC 5 一边追求 machine-independent,一边警告:
1 | |
这句话放到今天几乎不用改:
1 | |
软件开发者仍然会被:
- byte order;
- integer width;
- overflow;
- encoding;
- floating-point;
- alignment;
这些底层差异击中。
十、它是一种“应用特定协议由代码描述”的思路
传统协议是:
1 | |
RFC 8700 对 DEL 的历史概括更有意思:
他们设想 application-specific protocols,并把代码下载到用户站点。
也就是:
1 | |
今天我们可能会想到:
- downloadable schema;
- protocol plugins;
- eBPF-like programmable data path;
- Wasm plugins;
- server-driven client;
但仍需强调,这些只是现代类比,不是直接继承关系。
十一、DEL 失败的地方同样有价值
Steve Crocker 在 RFC 8700 回顾:
当 BBN 的 Host-IMP Interface 规范到来后,NWG 的注意力转向更紧迫的低层协议,自动下载代码的宏大设想消退。
这是很经典的工程现实:
1 | |
RFC 5 提醒我们:
系统抽象层次必须匹配基础设施成熟度。
如果底层连接、流控、地址、Host-Host Protocol 都还没稳定,再设计通用可下载网络语言,很可能过早。
这篇 RFC 带来的影响
RFC 5 没有成为今天 Internet Protocol Stack 的组成部分。
不能画成:
1 | |
这样的“线性祖先图”。
它的影响更适合从“思想和研究方向”来理解。
一、它把 RFC 1 中的 DEL 设想真正展开成了一套系统
RFC 1 已经提出:
1 | |
RFC 5 则真正回答:
1 | |
所以 RFC 5 可以看作早期 DEL 思路最完整的一次展开。
二、DEL 后续演化为更一般的 NIL 设想
RFC 8700 明确说:
1 | |
1970 年的 RFC 51《Proposal for a Network Interchange Language》 进一步提出:
Network Machine(网络机器)。
RFC 100 对 NIL 的总结是:
1 | |
并用多个 sublanguage 描述:
- Control;
- Operation;
- Data Declaration;
- Environment。
也就是说,DEL 最初聚焦:
1 | |
NIL 则开始走向:
1 | |
三、RFC 100 证明这条研究路线至少持续到了 1971 年
RFC 100 在 D.4 中专门设置:
1 | |
并总结 DEL:
1 | |
这说明 RFC 5 并不是发表以后马上无人问津。
它进入了早期 NWG 关于:
1 | |
的一整条讨论线。
四、它很早就提出“把计算移向用户”
RFC 5 写:
1 | |
这是整篇最值得记住的技术判断之一。
今天我们把计算移动到:
1 | |
通常也是为了:
1 | |
DEL 当然不是这些架构的直接来源,但它面对的是同一类分布式系统取舍。
五、它提供了一个非常早的 Code-on-Demand 历史案例
RFC 2555 中,Steve Crocker 回忆:
1 | |
并把 Jeff Rulifson 的 DEL 视为这一思路的实现尝试。
1999 年回顾时,他直接提到了:
1 | |
所以从互联网自身的官方历史叙述看,DEL 的确长期被记忆为一种:
远端下发程序、本地执行、协助网络交互的早期构想。
六、它留下了“中间表示优于两两适配”的经典架构思想
Universal Hardware Representation 解决的是:
1 | |
之间的组合爆炸。
这种问题今天仍然存在:
1 | |
常见解决方式仍然是:
1 | |
RFC 5 是这类思路在早期网络交互中的一个很鲜明案例。
七、它把“显示协议”从设备命令提高到了逻辑实体
RFC 5 的:
1 | |
是一种非常重要的抽象升级。
它把通信接口从:
1 | |
提升到:
1 | |
这种“传意图而不是传实现细节”的思想,在现代 API 与分布式 UI 设计中仍然非常有生命力。
八、它也展示了互联网设计并不是一条直线
RFC 5 最有历史价值的地方之一,是提醒我们:
互联网并不是从 NCP 一步一步“必然”升级成 TCP/IP,再“必然”出现 Web。
早期工程师同时探索过很多路线:
1 | |
有些成为主流。
有些被替代。
有些概念几十年以后以完全不同的技术形式再次出现。
RFC 5 就属于第三种中特别有意思的一篇。
总结
RFC 5 表面上是一份:
Decode Encode Language Specification。
但真正读进去以后,会发现它想解决的不是“怎样发明一门新语言”这么简单。
它面对的是一个完整的分布式交互问题:
1 | |
RFC 5 给出的整体答案是:
1 | |
其中几个关键设计尤其值得记住。
第一,不要为每一对异构设备都写一套转换器:
1 | |
第二,不要让所有交互都跨网络往返:
1 | |
第三,不要只传某台设备的低层命令:
1 | |
第四,不要把远程适配逻辑永久硬编码在每个用户站点:
1 | |
第五,语言本身必须理解网络和交互。
DEL 因此把:
1 | |
都直接放进语言模型。
它最终没有成为 ARPANET 的通用执行环境。
随着 Host-IMP Interface 和更底层 Host-Host Protocol 问题变得紧迫,早期自动下载代码的宏大设计逐渐退居次要位置;之后这条思路又继续演化为 RFC 51 的 NIL,以及其他 Network Language / Form Machine 研究。
但 Steve Crocker 三十年、五十年后的两次 RFC 历史回顾仍然专门提到了 DEL。
原因并不难理解。
因为它在 1969 年就问出了一个今天仍然非常现代的问题:
如果网络另一端拥有服务和状态,而用户这一端拥有屏幕、输入设备和低延迟执行能力,那么到底应该把哪些逻辑放在服务器,哪些逻辑放在客户端,又应该用什么可移植形式把两端连接起来?
今天我们会用:
1 | |
回答不同版本的这个问题。
RFC 5 的答案叫:
DEL。
它没有成为最终答案。
但在互联网真正上线之前,就有人已经开始认真思考这个问题了。