摘要
- Telnet 的网络虚拟终端没有统一所有主机,只统一了必要动作:
CR LF是“新起一行”,CR NUL是“只把位置退回本行左端”,默认 NVT ASCII 不允许裸CR。 CR后面的字节是一项可本地验证的证据;发送端选择共同动作,接收端再把它映射为自己的终端或操作系统行为。- RFC 1123 后来补清 Enter 键的输入歧义;Binary 模式取消行尾转换,Net-Unicode 则保留 CRLF、逐步收窄 CR NUL 的用途。
一枚尚未完成的字符
把早期终端看成一台打印机,CR 与 LF 就不是同义词。CR 让打印头回到本行左边,却不下移;LF 让它向下走一行,却保留横向位置。二者连在一起,才得到现代读者熟悉的“下一行开头”。
不同机器并不都能分别执行这两个动作。有的设备把回车与进纸绑定,有的主机只用 LF 结束一行,有的用 CR,还有的根本用记录长度或特殊分隔符。接收端若见到 CR 就立即动作,随后又独立处理 LF,结果可能重复;若一味等待,又不知道何时可以确定发送者只要回车。
RFC 318 在 1972 年把它写成一个有限等待问题:先保留 CR,再看下一字符。遇到 LF,就执行统一的换行功能;发送者若只想回车,则发送 CR NUL。NUL 对虚拟打印机不产生动作,却明确表示“这里没有配套的 LF”。
因此,空字节并非普遍无意义。它在特定位置完成语法,让沉默本身成为可解析的选择。
共同层只保留不可少的差别
RFC 854 把 Network Virtual Terminal 设为 Telnet 连接的初始共同表示。两端不必先交换完整的终端型号与操作系统习惯。每一端负责把本地行为变成 NVT 动作,并把收到的 NVT 动作再翻译回本地。
这不是一份全球终端政策。NVT 规定 NUL 无动作、LF 竖直下移、CR 回到左边;终端宽度、页长、字符转换、缓冲与本地驱动仍由端点决定。
RFC 854 同时把早期建议收紧为默认 NVT ASCII 规则:组合动作必须写作 CR LF,并作为一个“新行”处理;单独回车必须写作 CR NUL;其他位置不得出现 CR。该规则双向适用,即使双方都知道实际连接的是程序而非打印机。
接收 CR NUL 后,Telnet 要先去掉 NUL,再进行 NVT 到本地字符集的映射。这个 NUL 属于网络表示层,不天然属于应用正文。相反,在别的模式里擅自丢弃同一字节也可能毁坏数据。
Enter 键把本地意图重新带回问题
线上的二字节语法很清楚,人手按下 Enter 时却出现第二层歧义。用户是在要求“完成一行”,还是要求把 ASCII 的 CR 键原样交给远端字符型程序?
RFC 1123 记录了现实分裂:一些客户端发送 CR LF,另一些发送 CR NUL。对正确实现的 ASCII 服务器,两者作为终端输入都应产生本地行结束键的效果;非 ASCII 主机却可能在“保留真正的裸回车”与“兼容既有客户端”之间为难。
修正规则没有假装所有场景相同。User Telnet 必须能发送 CR LF、CR NUL 和 LF。ASCII 客户端宜让用户选择 CR LF 或 CR NUL,并以 CR LF 作为行结束键的默认值。对于服务器输出,或通过 Telnet 承载的其他应用协议文本,行尾必须使用 CR LF。
服务器仍掌握最后一段本地映射。原始终端模式可以向应用交付 CR;格式化模式则应用本机行尾规则。标准要求的是终端边界上的行为等价,并非所有内部缓冲区都保存相同字节。
Binary 不是“八位版 NVT”
RFC 856 的 Binary 选项需要逐方向协商。只有一端提出、另一端确认,该方向才进入二进制解释;反方向不会自动跟随。
进入 Binary 后,普通字节作为八位数据。Telnet 命令仍有边界:IAC 继续引出命令,数据中的 255 必须写成两个 IAC。但行尾解释停止。RFC 1123 明确禁止把 CR 改写为 CR NUL 或 CR LF。
这里发生的不是字符集变宽,而是解释权转移。在 NVT ASCII 中,CR 需要后一字节决定动作;在 Binary 中,CR、LF 与 NUL 都是应用数据,除非上层协议另有定义。只凭字节形状做“清理”,既可能误删 NUL,也可能凭空插入 NUL。
因此,故障记录不能只保存可见文字。方向、协商状态与原始 octet 必须在同一时间线上,才能判断转换是否越权。
Linemode 把编辑移近用户
RFC 1184 处理的是时延与逐字符交互成本。启用 Linemode 编辑后,客户端可以先在本地完成一行,再把正常行结束符写成 CR LF 发送。编辑关闭时,回车写成 CR NUL,LF 仍是 LF,无法映射成普通 ASCII、但含义是“完成此行”的按键写成 CR LF。
服务器输出的责任没有随编辑位置移动:新行仍用 CR LF,只回车用 CR NUL,只下移用 LF。优化把缓冲与编辑放到了更近的端点,却没有让客户端接管服务器输出的语义。
这条边界说明,性能布局与共同含义是两项独立决定。改变执行位置,不等于允许重写协议事实。
虚拟打印机退场,CRLF 留下
RFC 5198 在 Net-Unicode 中回顾了 NVT ASCII 的影响。它选用 UTF-8,并继续以 CRLF 表示行尾;同时保留 CR 必须紧接 LF 或 NUL 的结构限制。
不过,该文档建议尽量避免 CR NUL。现代文本能以组合字符和标记表达早期的叠印、版面效果,而 NUL 又可能被某些语言和库误作字符串终点。曾经必要的“只回车”动作,已不再值得在一般网络文本里广泛携带。
这不是说 1972 年的设计错误。它说明公共表示会分层老化:深度安装的 CRLF 继续承担行边界,依赖老式打印动作的例外逐渐缩小。
IANA Telnet Options registry 仍列出 Binary、Linemode 与回车处理等选项。登记只能证明编号与名称稳定,不能证明当下部署数量或产品实现质量。
过早归一化会抹掉谁的决定
这套机制的权力分配很薄。发送者声明共同动作;接收者读取相邻字节即可本地验证;端点各自决定本机映射;双方同意后,Binary 等模式才改变解释器。
风险来自越过顺序。网关尚未读到协商状态便统一行尾,客户端过早把 Enter 固定成换行,字符串库在 NUL 处截断,日志只保留渲染结果。共同规则本来给出了答案,工具却先销毁了答案。
来源与证据边界
- https://www.rfc-editor.org/rfc/rfc318.html
- https://www.rfc-editor.org/rfc/rfc854.html
- https://www.rfc-editor.org/rfc/rfc856.html
- https://www.rfc-editor.org/rfc/rfc1123.html
- https://www.rfc-editor.org/rfc/rfc1184.html
- https://www.rfc-editor.org/rfc/rfc5198.html
- https://www.iana.org/assignments/telnet-options/telnet-options.xhtml
这些官方文档能够证明协议模型、修正过程、协商例外与登记词汇,不能测量当前 Telnet 使用率,不能认证某款产品的默认行为,也不能证明历史实现从未分歧。本文只讨论 CR NUL 在明确模式与方向中的表示责任。
会员简报
档案背景详情
使用相应会员等级登录,即可解锁完整简报与来源注释。
仅限 Strategic Circle
Strategic Circle
所有读者均可浏览。加入并登录后可解锁档案简报。
加入 Strategic Circle仅限 Leadership Alliance
Leadership Alliance
符合条件的 IP 资产所有者和管理层可登录查看 Leadership Alliance 简报。
加入 Leadership Alliance
