# mosh

当网络不配合时，mosh 能让会话保持存活：从 Wi-Fi 切到蜂窝网络、合上盖子、走出
信号范围 —— 重新连接后，会话还在那里。Tessera 为它搭配了 iOS 上其他 mosh 客户端
都没有的东西：**真正的回滚缓冲**。

mosh 要求主机上安装了 `mosh-server`，并且默认开放 UDP 端口 60000–61000。可在
[主机编辑器的传输方式设置](https://bambouville.com/docs/zh-hans/connections/#传输方式ssh-或-mosh)中按主机选择它。

## 漫游

mosh 会话绑定的是你的身份，而不是网络路径。Tessera 会在 Wi-Fi ↔ 蜂窝网络切换、
地址变化以及睡眠/唤醒之间保持接入 —— 会话就从数据包中断的地方继续下去。在 VPN
或 tailnet 上同样如此；mosh 只需要 UDP 能到达服务器。

## 真正的回滚缓冲

原版 mosh 没有回滚缓冲 —— 它在设计上只同步可见的屏幕，因此滚出屏幕的内容根本不会
被发送。其他所有 iOS mosh 客户端都继承了这个限制，并让你去用 tmux 的复制模式。

Tessera 则会把历史合成出来。在由 tmux 支撑的 mosh 会话中，终端跑在 UDP 上，
同时有第二条 SSH 侧信道与 tmux 通信；向上滚动会通过该信道拉取真实的历史并就地
显示 —— 可用[在终端中查找](https://bambouville.com/docs/zh-hans/keyboard/#在终端中查找)搜索、可选中、完整无缺。

![Tessera 中的一个 mosh 会话向上回滚，浏览一长段 git log，提交信息和 diffstat 完整呈现，下方可见 shell 提示符。](https://bambouville.com/docs/assets/img/mosh-scrollback.png)

*一个 mosh 会话深入回滚到 git log 中 —— 这些历史原版 mosh 早就丢弃了。*

在你阅读时，它的行为是这样的：

- 向上滚动会让历史**定格在原处** —— 新输出不会把你拽回底部。
- 回到底部（或开始输入）会撤下这层覆盖，回到实时的最新画面。
- 用力一甩会一直滚下去：第一页立即加载，其余历史随后流式补上，直到服务器保留
  的深度为止。

## 它需要什么

- **一种 tmux 启动模式。** 回滚缓冲合成适用于**自动 tmux**和**具名 tmux**会话
  （自动 tmux 是默认值）。以自定命令启动的 mosh 主机没有 tmux 可询问，因此它
  的滚动和原版 mosh 一样。
- **服务器端历史。** 深度受服务器 tmux `history-limit` 的限制 —— Tessera 只能
  显示 tmux 保留下来的内容。
- **主屏幕。** 像 `vim`、`less` 和 `htop` 这样的全屏程序自己处理滚动；Tessera
  会像所有终端一样，把你的滚动作为输入转发给它们。

## mosh 与其他一切

获取历史所用的同一条 SSH 侧信道，也承载着 mosh 主机的
[tmux 窗口与窗格](https://bambouville.com/docs/zh-hans/tmux/)和[端口转发](https://bambouville.com/docs/zh-hans/port-forwarding/#mosh-与转发)，而
[文件面板](https://bambouville.com/docs/zh-hans/files/)会打开它自己的 SSH 桥接 —— 因此文件传输和隧道在 mosh 和
纯 SSH 上表现完全一致。

有一点需要注意：**mosh 的 UDP 无法穿过 SSH 跳板主机**。对于
[经跳板链连接的主机](https://bambouville.com/docs/zh-hans/connections/#跳板主机)，Tessera 会先尝试 mosh，如果
服务器在 UDP 上不可达则回退到 SSH。若目标本来就能通过 UDP 到达 —— 比如经由
VPN 或 tailnet —— 它仍会以 mosh 方式继续工作。
