"Broken pipe" / "client_loop: send disconnect" 是什麼意思
你的 SSH 工作階段死了,因為底下的 TCP 連線沒了——典型是閒置一段時間之後。packet_write_wait: Broken pipe 和 client_loop: send disconnect: Broken pipe 是同一個故事的兩個角度:客戶端往一條已經不存在的連線裡發資料。這不是認證或伺服器問題,是連線存活問題,三個經典元兇:NAT 路由器靜默丟棄閒置連線、網路在你腳下變了(Wi-Fi ↔ 行動網路)、以及任一端激進的閒置逾時設定。
三個元兇
| # | 元兇 | 規律 |
|---|---|---|
| 1 | NAT/路由器閒置逾時 | 安靜 N 分鐘後死;一直打字就沒事 |
| 2 | 網路在腳下變了 | 走出 Wi-Fi 範圍 / 切網路時死 |
| 3 | 設定的閒置斷線 | 伺服器的 ClientAliveInterval/CountMax 在關安靜工作階段 |
修法 1——心跳保活(標準解)
保活發送微小的心跳封包,讓 NAT 表和閒置計時器永遠看不到"安靜"的連線。客戶端(~/.ssh/config):
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
# = 每 60 秒 ping 服务器一次;丢 3 次就放弃 或伺服器端(/etc/ssh/sshd_config),涵蓋包括行動 App 在內的所有客戶端:
ClientAliveInterval 60
ClientAliveCountMax 3 兩者有其一通常就能整類消滅閒置掉線。行動客戶端在前臺時一般會發自己的保活——伺服器端設定是無論什麼客戶端都生效的雙保險。
修法 2——接受行動網路會漫遊,提前安排
手機從 Wi-Fi 跳到行動網路時,TCP 連線的位址變了——普通 SSH 不可能挺過去;無論保活怎麼設,工作階段都會斷。你的選項:
- mosh——為漫遊而生(UDP,不綁位址)。需要裝在伺服器上;沒有通道/SFTP。見 Mosh vs SSH。
- 穩定位址上的快速重連——行動端的務實答案:走 Tailscale,伺服器在每個網路上都是同一個位址,重連就是一下點擊、什麼都不用重填。TermAI 內建 Tailscale,重開工作階段回到原處。
- 伺服器上的 tmux/screen——無論連線怎樣,你的工作活著:
tmux attach重新掛上,跑著的程序還在。和上面任一選項完美配合。
修法 3——長任務本來就不該指望你的工作階段
如果掉線殺死了一個長任務,持久的習慣是壓根別把任務綁在你的終端上:跑在 tmux 裡,或 nohup long_command &。在手機上這一點加倍重要——長等待中作業系統可能掛起 App。任務分離地啟動,放心關 App,稍後回來看。
常見問題
為什麼我的 SSH 工作階段閒幾分鐘就死?
NAT 路由器或閒置計時器丟棄了安靜的連線。客戶端設 ServerAliveInterval 60 或伺服器設 ClientAliveInterval 60。
SSH 能挺過 Wi-Fi 切行動網路嗎?
普通 SSH 不能——位址變了。用 mosh(挺得過漫遊),或穩定的 Tailscale 位址做一鍵即時重連,伺服器上配 tmux 保住工作。
怎麼不讓長任務跟著連線一起死?
分離執行:tmux/screen 裡,或 nohup。任務從此比任何掉線都活得久。
快速事實
- 含義:TCP 連線死了(通常被閒置丟棄),不是認證/伺服器的錯
- 標準解:保活——客戶端
ServerAliveInterval 60或伺服器ClientAliveInterval 60 - 網路漫遊:普通 SSH 挺不過——mosh,或穩定位址 + 快速重連
- 保住工作:tmux/nohup,讓任務比工作階段長壽
Free on iOS and Android. 5 AI requests/day on the free tier, plus unlimited SSH/SFTP and built-in Tailscale.