摘要

  • 早期 FTP 断点由发送端与接收端各自保存位置,必要时连同落盘状态和字符转换状态一起恢复;后来 REST STREAM 才把位置化成传输字节数。
  • 偏移量属于某一次传输表示,不是文件版本标识。路径、长度或 350 回复都不能单独证明旧前缀与新后缀来自同一对象。
  • RFC 3659 的续传示例在发出 REST 前明确说明远端文件已确认没有改变。这项确认不是命令的效果,而是命令能够安全使用的前提。

802816 之后仍缺一个答案

设想一个大文件下载到 802816 字节时连接断开。客户端重新登录,设为 Image 类型,发送 REST 802816。服务器回答 350,下一条 RETR 从后面继续。

这段交互证明服务器愿意把一个数保存给下一次传输。它没有证明路径指向的内容仍是原来的版本,也没有核对客户端手里的 802816 字节是否真的就是该版本的前缀。若远端文件已经替换,新后缀仍可能被顺利接到旧前缀后面。

断点让进度可复用,却没有让对象身份自动随进度一起保存。

最早的标记并不是通用字节数

RFC 765 已把断点恢复列入 FTP 的错误恢复机制。REST 本身不传文件,只让服务器移动到一个标记,随后必须紧接原来中断的服务命令。

当时没有理由把标记规定成统一磁盘偏移。FTP 面对的主机可能使用不同字长、字符集、行尾与记录结构。逻辑字节和线上固定八位的传输字节不是同一概念;TYPE、STRU 与 MODE 会共同决定存储内容如何变成数据连接上的序列。

RFC 959 延续了这一模型。Block 与 Compressed 模式的流带有格式,因而可以把断点标记作为特殊块嵌入,而不与文件正文混淆。发送方保存自己能识别的位置,接收方把它对应到本地落盘位置。双方不必共享同一种文件系统坐标,只需各自在重启时读懂自己生成的状态。

一个检查点包含两种本地现实

RFC 1123 修正了 RFC 959 对 110 回复的说明。新的表述把发送端位置 ssss 和接收端对应位置 rrrr 配成一对。两者可以是实现私有的字符串,因为日后解释它们的仍是各自原来的系统。

接收方报告位置前,还应把此前数据写入稳定存储。否则,标记声称可以恢复的字节可能与导致中断的故障一起消失。这里保存的是“已经持久化的进度”,而不是“网络上曾经看见的进度”。

位置还可能带着转换器的内部状态。RFC 1123 举例说,TYPE A 接收方可以把线上 CR LF 转成磁盘上的一个 LF。如果标记恰好落在 CR 与 LF 之间,接收方必须记住 CR 已经被看到并丢弃。单独的磁盘字节号无法告诉重启后的转换器下一字节该如何解释。

因此,文档又定义了 554 表示位置无法恢复,555 表示现有部分文件与当前 TYPE 或 STRU 不匹配。一个格式正确的标记仍可能没有可执行的含义。

STREAM 把标记变成了数数

这套成对标记能力很强,却不轻。RFC 1123 在 1989 年把 Restart、ABOR 与 Block mode 称为有价值但并未广泛实现的健壮性功能,且没有把 REST 放入最小命令集。这是当时的历史观察,不是今天的部署统计。

Stream mode 没有可区分的控制块:插进去的标记会与正文八位字节无法区分。RFC 3659 因而给出更直接的规则:REST STREAM 后面的十进制数,表示紧接着的传输需要跳过多少个线上字节。

客户端也不用猜服务器是否支持这种语义。服务器应通过 RFC 2389 定义的 FEAT 机制声明 REST STREAM。能力声明解决的是“会不会执行”,不是“现在这份文件是不是原来的版本”。

数数也没有消灭表示转换。RFC 3659 用同一份文本说明:TYPE I 下 SIZE 是 1830,TYPE A 下却是 1942,因为行尾转换增加了传输字节。偏移量属于按当前参数将要发送的流,未必等于本地文件系统中的原生位置。

上传恢复尤其需要服务器报告已经正确收到并保存了多少数据。SIZE 可以给出当前表示下的长度,却仍只是长度,不是已存前缀的摘要。

成功恢复位置,不等于恢复对象

RFC 3659 的示例在使用 802816 这个数之前,先交代两件事:上次使用 TYPE I,而且已经验证服务器上的文件此后没有改变。

后一句划出了协议边界。REST 不会替客户端完成这项验证。同一路径可以被新内容占用,同样长度也可以属于两个不同版本;只要新文件足够长,旧前缀与新后缀甚至可能组成一个结构上完整、语义上错误的混合物。

上传方向的边界更严。RFC 3659 只把 REST 定义为完成此前失败的传输。如果位置不在服务器现存数据末端,或后续 STOR 提供的数据不足以把目标扩展到原有长度,结果未定义。允许 APPE 也不能改变含义:它必须像从指定位置写入的 STOR 一样工作。

350 只是把状态留给下一条命令

REST 必须紧挨着真正的数据传输命令。服务器可以先用 350 接受标记,直到 RETR 或 STOR 到来才发现越界或无法定位。若客户端未能成功发出下一条命令,就应再次发送 REST,而不是相信早先保存的状态会跨越任意对话。

完整的恢复状态实际分散在部分文件、传输参数、服务器能力、标记、命令顺序与对象身份检查之中。只留下一个数,相当于只保存了状态机最醒目的那一格。

来源与证据边界

早期命令来自 RFC 765,经典传输模式来自 RFC 959,成对位置、稳定存储与转换状态来自 RFC 1123,能力发现来自 RFC 2389,STREAM 偏移、SIZE 与示例来自 RFC 3659。这些文档不能证明当前部署比例,也不能证明任何服务器会保留历史版本。FTP 续传不是认证、内容哈希、存储快照或恰好一次传输。