SSD Nodes Learn 🎉 VPS $5.50/月起
指南 Matt Connor作者: Matt Connor · 已更新 2026-08-16

從 Kermit 到 rsync:檔案傳輸協定 45 年演變

Kermit 歡度 45 週年並推出 C-Kermit 11.0.506。了解檔案傳輸如何從雜訊電話線、NAT 後的 FTP,演變為 SSH 上的 rsync 與 SFTP。

檔案傳輸協定為何持續變更

每種檔案傳輸協定,都是針對其所處年代的特定故障模式設計。Kermit 假設線路會損毀傳輸中的位元組。XMODEM 和 ZMODEM 假設連線速度很慢,而且每多連線一分鐘都要付費。FTP(file transfer protocol)假設中間的網路會正常轉送流量。SSH 則假設網路環境不可信。最後一種假設勝出,因此現在的 VPS 通常提供 SSH 上的 SFTP 和 rsync,其他選項則很少。

現在重新檢視這段歷史,正是合適的時機。C-Kermit 11.0.506 於 3 August 2026 released。這是自 20 August 2011 的 C-Kermit 9.0.302 以來,第一個非 beta 版本;而它實作的協定設計於 May 1981。四十五年足以見證一整類技術被發明、標準化、遭到其運作所在的網路破壞,最後納入 SSH。

Kermit, 1981:為會吞掉位元組的線路而設計

Kermit 由 Frank da Cruz 與 Bill Catchings 於 1981 年 5 月在 Columbia University Computer Center 建立。名稱取自 Kermit the Frog。Da Cruz 表示,當時團隊正在討論名稱,牆上剛好掛著一幅 Muppets 月曆,沒有人預期這項技術會廣泛流傳。

Kermit 解決的問題不是速度。終端機與 mainframe 之間的路徑,不是可傳送任意位元組的管線,而是具有特定限制的字元裝置。它可能只支援 7-bit,可能是半雙工,也可能吞掉控制字元,或將其中一個控制字元當成命令執行。未經修改地透過這類路徑傳送 binary file 並不可行。

因此,Kermit 的設計直接納入這些限制。Kermit Project 的歷史資料列出以下設計:

  • 使用短封包,因為多數 mainframe 無法從終端機接收長時間的大量資料
  • 使用半雙工的 stop-and-wait,因為 IBM mainframe 不支援全雙工通訊
  • 將控制字元與 8-bit 字元編碼為可列印字元,因為兩者都無法通過 mainframe 的終端機驅動程式
  • 每個封包都附加 checksum,並由接收端回覆,因此封包毀損時只需重傳該封包,不必重傳整個檔案

第三點尤其值得注意。Kermit 傳送的是檔案的 text-safe 編碼,而不是檔案本身。控制位元組會轉換成前綴字元加上可列印字元;設定最高位元的位元組,也能用相同方式編碼,以通過 7-bit 連線。路徑中任何只理解可列印文字的設備,看到的都是可列印文字。代價是資料量增加:binary file 在傳輸線路上會變大。對於原本會完全破壞傳輸內容的 mainframe front end,這是正確的取捨。

Kermit 的另一項特殊性在於其適用範圍。XMODEM 用於兩台已對檔案定義達成共識的機器之間傳送檔案。Kermit 則是不同系統之間的最低共同標準;這些系統可能使用不同字元集、不同記錄結構,也可能對文字行結束方式有不同定義。這正是從 mainframe 遷移至 cloud server 的漫長過程所描述的世界。在 network layer 為你處理互通性之前,Kermit 就是互通性的實作方式。

Columbia 於 2011 年結束贊助,並依修訂版 3-clause BSD licence 發布 C-Kermit。Frank da Cruz 持續參與此專案 44 年,從 1981 年的設計一直到 2025 年。2026 release 由 OpenKermit project 維護,John Goerzen 負責將這套比目前多數讀者年齡還大的 C codebase 現代化。

XMODEM 與 ZMODEM:電話費如何影響設計

Ward Christensen 在 1977 年撰寫了 MODEM.ASM,而該程式引入的通訊協定就是 XMODEM。1978 年,他與 Randy Suess 將 CBBS 上線,建立了第一個公開的電子佈告欄系統。Christensen 於 2024 年 10 月 11 日逝世。

XMODEM 幾乎已經是最精簡的通訊協定。資料以 128-byte 區塊傳送。每個區塊都包含 1-byte checksum,也就是 128 個資料 byte 的總和再對 256 取模。接收端會確認每個區塊,或要求重新傳送。這種設計源自經濟考量。撥接線路按使用時間計費,因此線路錯誤只應造成 1 個區塊重傳,而不是整個傳輸重新開始。

弱點也就在同一句話中。XMODEM 每傳送 128 bytes 就要等待確認。Chuck Forsberg 在 ZMODEM 規格中明確指出:「短區塊長度用於分時系統、封包交換網路及衛星電路時,會使吞吐量下降。」造成 stop-and-wait 效能低落的是延遲,而不是頻寬。在按時間計費的線路上,每次往返等待都代表一段沒有傳輸的時間。

接著出現 YMODEM,名稱由 Ward Christensen 於 1985 年命名。它的貢獻是批次傳輸。傳送端會在資料前先提供檔名與大小,因此可在同一個工作階段傳送多個檔案,接收端也能知道每個檔案的結束位置。

ZMODEM 是 Chuck Forsberg 在 Omen Technology 撰寫的解決方案。其規格版本為 14 October 1988,並指出:「ZMODEM 是在 Telenet 合約下為公有領域開發的。」Telenet 經營公開的封包交換資料網路,而該合約反映在設計中。ZMODEM 會跳脫網路控制字元,避免中間的封包網路消耗這些字元。它以獨特的字元序列標示每個 frame 的開始,而不是從沉默推斷 frame 邊界,因此遇到雜訊時不必等待 timeout 就能恢復。它也提供明確的 resume 功能,讓中斷的傳輸從停止的位置繼續。

最重要的是,它不再持續等待。規格本身的描述是:「ZMODEM 實際上將整個檔案作為 window 使用。」傳送端會持續串流,只有在接收端回報問題時才停止。這與 TCP 在 window 中實作的概念相同,只是從另一個方向得到這項洞見:有人注意到 modem 閒置卻仍在計費。

FTP 的雙連線為何逐漸難以維護

FTP 比這些技術都早。RFC 114《檔案傳輸通訊協定》(A File Transfer Protocol)的日期是 16 April 1971,作者為 A. Bhushan。

值得注意的是,RFC 114 曾考慮雙連線設計,但最後否決。Bhushan 評估「使用兩條全雙工連結,一條傳送控制資訊,另一條傳送資料」,接著得出結論:「我們建議使用單一全雙工連線,同時交換資料與控制資訊。」雙連線設計是在之後才出現。日期為 8 July 1972 的 RFC 354 指出,「資料與檔案只能透過資料連線傳輸」,命令則透過獨立的 Telnet 連線傳送。由 Postel 與 Reynolds 撰寫、發布於 October 1985 的 RFC 959,就是目前仍普遍實作的版本。

RFC 959 也確定了連接埠。伺服器的預設資料連接埠是「緊鄰控制連線連接埠的連接埠(亦即 L-1)」,因此控制連線使用連接埠 21 時,資料連線使用連接埠 20。

但其中有一項設計未能延續。在 FTP 的原始模式中,資料連線由伺服器回頭建立至用戶端。位於 NAT(network address translation)後方的用戶端沒有伺服器可連線的位址;位於防火牆後方的用戶端則不接受輸入連線。因此,資料連線不會建立,使用者要求目錄清單或檔案後,傳輸就會停滯。解法是 PASV。RFC 959 將其定義為要求伺服器「在資料連接埠上『監聽』(該連接埠不是預設資料連接埠),並等待連線,而不是在收到傳輸命令後主動建立連線」。伺服器會回覆可供連線的位址與連接埠:

PASV
227 Entering Passive Mode (203,0,113,10,195,80)

該回覆表示主機為 203.0.113.10,連接埠為 195 乘以 256 再加上 80,也就是 50000。重新閱讀一次,就能看出其中的結構性問題。第二條連線的端點,會放在第一條連線的有效負載中公告。NAT 設備或防火牆必須解析控制通道,並開放其中指定的連接埠,才能通過這條連線。Linux 隨附的連線追蹤 helper 正是負責這項工作。該 helper 只有在控制連線使用明文時才能運作,因此以 TLS(transport layer security)包裝 FTP 後,原本讓 FTP 能夠運作的中間設備就無法辨識內容。

這就是 FTP 的一段話教訓:它讓網路成為通訊協定的參與者。需要網路理解自身內容的通訊協定,無法在網路不再信任該協定時繼續運作。

結局已有正式紀錄。Firefox 在 July 2021 的 version 90 移除 FTP 支援。Chrome 在 October 2021 的 Chrome 95 移除 FTP 程式碼。

rcp 與 r-commands:依主機名稱建立信任

4.2BSD 由 Berkeley 在 DARPA 資助下於 1983 年發布,帶來了 rcp、rsh 和 rlogin。這些工具是為同一網路上的 Unix 校園機器所設計,其驗證模型也反映了這一點。主機會宣稱發出請求的使用者身分。如果 /etc/hosts.equiv 或使用者的 ~/.rhosts 表示該主機受信任,系統就會接受這項聲明,不要求輸入密碼。

必須直接說明其運作方式,因為這正是這些指令遭淘汰的原因。信任建立在位址與聲明上。兩者都以明文經由網路傳送,因此路徑上的任何人都能讀取,也能偽造。這種模型適用於 從 Unix 到 Linux 的發展歷程 所描述的環境,當時網路只涵蓋一棟建築。網路一旦成為 internet,這種模型就不再合理。

rcp 做對的是介面。指定來源、指定目的地,完成。不需要開啟工作階段,不需要協商傳輸模式,也不需要安排第二個連線。它的行為類似路徑中含有冒號的 cp。這個介面比其通訊協定多存續了 40 年。

SSH 涵蓋了整個類別

1995 年,當時任職於 Helsinki University of Technology 的研究人員 Tatu Ylonen,因應校園網路遭遇的密碼側錄攻擊而撰寫 SSH。他在 1995 年 7 月以附帶原始碼的 free software 形式發布。到了同年年底,估計已有約 20,000 名使用者分布在 50 個國家;同年 12 月,他成立 SSH Communications Security,持續進行開發。

後續版本收緊了授權條款,因此 OpenBSD 開發人員從最後一個採用自由授權的版本 ssh 1.2.12 建立 fork。首次匯入發生於 26 September 1999,而 OpenSSH 1.2.2 隨 OpenBSD 2.6 於 1 December 1999 發布。這個 fork 是一個精簡的實例,說明開放原始碼授權條款為何在實務上很重要,因為如今幾乎所有人使用的 SSH 實作,都源自那個授權仍允許繼續使用的版本。

SSH 出現後,檔案傳輸不再是獨立問題。經過驗證與加密、可承載多個 channel 的串流,已經提供舊協定必須自行建立的功能:完整性、順序控制,以及不需要第二條 TCP 連線的第二條資料路徑。如果你不熟悉這些機制,請先從 SSH 的實際定義開始,再繼續閱讀。

SSH 衍生出兩個工具。scp 是在 SSH session 內執行的 rcp 線路協定,因此完整繼承了 rcp 的命令列介面。SFTP 則是不同的設計:它是真正的檔案協定,具備目錄列出、檔案屬性與隨機存取功能,並透過 SSH channel 傳輸。SFTP 從未成為 RFC。IETF 草案 draft-ietf-secsh-filexfer 在 18 July 2006 達到第 13 版,之後便失效。OpenSSH 實作了該草案的第 3 版。全球使用最廣泛的安全檔案傳輸協定,是一份已遭放棄草案的編號修訂版,但它確實能正常運作。

傳統的 scp 協定現在也已退役。OpenSSH 8.8 於 26 September 2021 發布,並警告「OpenSSH 將在不久後的版本中,將 scp(1) 從使用傳統的 scp/rcp 協定切換為預設使用 SFTP」。OpenSSH 9.0 於 8 April 2022 發布,並完成這項變更:「本版本將 scp(1) 從使用傳統的 scp/rcp 協定切換為預設使用 SFTP 協定。」

這項原因解釋了一則常見的經驗法則。舊版 scp 協定會將遠端檔名萬用字元交給遠端 shell 展開,因此使用者才會學到,遠端路徑中的每個中繼字元都必須加上雙引號。8.8 的發布說明指出,透過 SFTP 的 scp「不再需要這種繁瑣且脆弱的引號處理」。因此,在目前的伺服器上,scp 是使用 rcp 命令列介面的 SFTP client。1983 年的介面保留了下來,但 1983 年的線路協定已不復存在。

rsync, 1996:傳送差異,而不是整個檔案

Andrew Tridgell 與 Paul Mackerras 於 1996 年 6 月 19 日在 Australian National University 發表 rsync,同時發布技術報告 TR-CS-96-05《The rsync algorithm》。

在 rsync 之前,所有通訊協定都在思考如何傳送檔案而不造成損壞。rsync 則改問:對方已經擁有這個檔案的多少內容?該報告將目標描述為「低頻寬、高延遲的雙向通訊連結」,並將目標定義為找出「來源檔案中與目的地檔案某些部分相同的部分」,讓系統只傳送不相符的內容。

這套機制值得理解,因為它能說明 rsync 的行為。接收端會將現有副本切成固定大小的區塊,並為每個區塊計算兩個 checksum:一個較弱且計算成本低,另一個較強且計算成本高。接收端將這份清單傳給傳送端。傳送端以每次 1 byte 的方式,讓視窗逐步掃描自己的檔案,並增量更新弱 checksum。這使得逐 byte 掃描仍具可行性。找到弱 checksum 相符後,再以強 checksum 確認。確認相符的內容會轉換為區塊參照。其餘內容則以 literal bytes 傳送。接收端利用既有區塊的參照,以及剛收到的 literal bytes,重新組合檔案。

如果在大型檔案開頭插入 1 byte,簡單的差異工具就必須傳送整個檔案,因為每個 offset 都已經改變。rolling window 會在新的 offset 找到相同區塊,因此 rsync 只需傳送 1 byte 加上必要的管理資訊。這項特性使 rsync 至今仍適合用於會重複複製的目錄。

有兩種行為經常讓使用者感到意外,而且兩者都記載於手冊中。第一,rsync 不會先為檔案計算 checksum,藉此決定是否檢查檔案。它「預設使用 quick check 演算法找出需要傳送的檔案;該演算法會檢查檔案大小或最後修改時間是否變更」。如果檔案內容已變更,但大小與 timestamp 維持不變,rsync 就會略過該檔案。--checksum 會改變這項行為,讓兩端完整讀取每個候選檔案。第二,當兩個路徑都是本機路徑時,delta algorithm 預設停用,因為在同一台機器上讀取並計算兩份副本的 checksum,成本高於直接複製 bytes。只有在連線速度較慢時,這項機制才有節省效果。

VPS 上實際會使用的工具,以及原因

簡而言之:傳輸少量檔案時使用 SFTP;要重複複製整個目錄時,使用透過 SSH 執行的 rsync。

兩者都透過 SSH 傳輸,因此無須額外設定,就能使用主機金鑰驗證與加密。這相當於把 50 年的技術成果壓縮成預設功能。Kermit 的設計者必須假設傳輸線會損毀資料,因此將 checksum 與重新傳輸機制內建於通訊協定中。現在由 TCP 負責這些工作。Christensen 與 Forsberg 必須假設每個位元組都會產生成本,因此加入續傳與串流功能。現在 rsync 的差異演算法負責這些工作,而且做得更好。FTP 的作者假設網路由彼此合作的主機組成;在這些假設中,只有這項假設被證明是錯誤的,而且無論投入多少通訊協定工程,都無法修正這個問題。

checksums 還能發揮什麼作用

「checksum」一詞在這段歷史中曾經扮演三種不同的角色,而且彼此不能互換。

Kermit 和 XMODEM 的逐封包 checksum 用來偵測網路傳輸中的資料損毀。如今這項工作由 TCP checksum 和鏈路層的錯誤更正機制負責,因此現代傳輸工具不會要求你特別處理這件事。

rsync 的區塊 checksum 並不是用來回答「這些資料是否正確」。它回答的是「你是否已經擁有這個區塊」。這裡的強 checksum 是查找鍵,而不是用來證明檔案來源的聲明。

第三種用途仍然需要由你處理。發布檔案上的公開 checksum 能回答 TLS 無法回答的問題。TLS 能證明你連線到正確的伺服器,但無法證明該伺服器上的檔案就是正確檔案;如果檔案是從 mirror 取得,TLS 也無法提供保障。因此,花三十秒檢查發布檔案的 checksum 和簽章仍然值得,而且很容易養成習慣:檢查每個要安裝之下載檔案的 checksum

這個故事中的其他問題都由下層機制解決了。只有這個問題沒有,因為它從來就不是網路問題。

FAQ

FTP 在 VPS 上是否仍可安全使用?

不安全。純 FTP 會以明文傳送認證資訊與檔案內容,因此路徑上的任何人都能讀取兩者。FTP 也依賴能解析控制通道的防火牆;控制通道一旦使用 TLS 加密,這種解析便無法進行。瀏覽器早已移除 FTP 支援:Firefox 在 2021 年 7 月的 version 90 移除 FTP 支援,Chrome 則在 2021 年 10 月的 version 95 移除相關程式碼。請改用 SSH 上的 SFTP。SFTP 只需要一個埠,也不需要能辨識協定的中介設備。

FTP 為什麼需要被動模式?

因為在 FTP 的原始模式中,伺服器會反向開啟資料連線至用戶端。RFC 959 將伺服器的預設資料埠設為「鄰接控制連線埠的埠,也就是 L-1」,因此控制埠為 21 時,資料埠就是 20。位於 NAT(network address translation)後方的用戶端沒有伺服器可連線的位址,因此該連線永遠無法抵達,傳輸也會卡住。PASV 會反轉連線方向:伺服器改為監聽,並在 227 Entering Passive Mode 回覆中提供位址與埠,讓用戶端連線至該位置。

scp 是否仍使用自己的協定?

自 OpenSSH 9.0 起便不是。OpenSSH 9.0 於 2022 年 4 月 8 日發布,並「將 scp(1) 從使用舊版 scp/rcp 協定改為預設使用 SFTP 協定」。OpenSSH 8.8 已在 2021 年 9 月宣布這項變更。可見的差異在於引號處理。舊版協定會將遠端萬用字元傳給遠端 shell 展開;以 SFTP 為基礎的新版本則不會。因此,依賴該 shell 展開的路徑,現在的行為會有所不同。

在 VPS 上,何時 rsync 比 scp 更適合?

當你會複製同一個目錄樹超過一次時。rsync 只會傳送目的端尚未擁有的檔案部分,因此第二次複製的成本會遠低於第一次。對於目的端從未見過的單一檔案,scp 與 rsync 傳送的位元組數大致相同,而 scp 更簡單。請注意,rsync 預設會依檔案大小與修改時間判斷要檢查的內容。因此,如果檔案內容已變更,但大小與時間戳記未變,必須先執行 --checksum,rsync 才會發現變更。

Kermit 為什麼要將檔案編碼為可列印文字,而不是直接傳送原始位元組?

因為它所針對的連線是通往大型主機的終端機線路,而不是位元組管道。這類連線可能只有 7-bit,而大型主機的終端機驅動程式會處理控制字元,而不是直接轉送它們。Kermit 將控制位元組與高位元位元組編碼為可列印字元,避免中間設備對其產生反應。這種編碼會使二進位檔案在網路上傳輸時變大,但相較於檔案傳輸後毀損,這是正確的取捨。