Files
NetMesh/docs/research/issue-2121-mosh-upstream-audit.md
zhaolei 3c72efcb7f
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
[Init] Initial commit - NetMesh terminal manager
2026-09-13 18:24:01 +08:00

214 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Issue #2121: MoshCatty 与官方 Mosh 的实现对照
研究日期2026-07-15
## 结论
最新的 MoshCatty 主分支已经修复了 #2121 背后最重要的协议和显示问题:高延迟下的并行状态会按各自声明的旧状态重建,不再把多个增量依次叠到当前画面;预测回显也已经改为“远端画面、预测覆盖层、最终差异输出”这一条显示路径。这两点分别解决字符重复和预测字符被画两次的问题。
交付状态已经推进到最后一段:
1. [`moshcatty-0.1.7`](https://github.com/binaricat/MoshCatty/releases/tag/moshcatty-0.1.7) 已公开发布四个平台文件和校验文件均已下载核对Netcatty 也能自动解析并取得该版本。
2. Netcatty 的配套改动仍在 [PR #2231](https://github.com/binaricat/Netcatty/pull/2231),尚未进入主分支;该 PR 会拒绝低于 `0.1.7` 的客户端,并已用正式 0.1.7 文件完成 macOS、Windows、Linux x64 和 Linux arm64 打包。
3. 已新增 Windows ConPTY 自动检查,覆盖密码提示、无结尾换行的握手信息、客户端切换和切换后的输入传递。它仍不能完全替代“正式 Windows 安装包 + Netcatty 页面”的人工视觉验收。
4. 已在完全隔离的网络中,用公开发布的 MoshCatty 0.1.7 对 Ubuntu 官方 `mosh-server` 1.4.0 完成高丢包、非对称延迟、乱序、重复包、65 秒完全断网、IPv6 最小 MTU 和 30 分钟持续压力测试;所有输入均按顺序且只执行一次,未发现新的协议缺陷。详细依据和可复现脚本见[网络压力验收报告](./issue-2121-network-stress-primary-sources.md)与[测试脚本](./issue-2121-netns-stress.sh)。
因此,当前判断是:核心方向已经与官方 Mosh 对齐没有证据支持重写0.1.7 发布门槛已经完成,合入配套 PR 和 Windows 正式产品页面验收仍是关闭 #2121 前的硬门槛。
## 版本与资料口径
本报告固定对照以下版本:
| 对象 | 版本 |
|---|---|
| 官方 Mosh | [`mobile-shell/mosh@decd9b7`](https://github.com/mobile-shell/mosh/commit/decd9b705eb81626f694335b8d5940538beb06da) |
| MoshCatty | [`binaricat/MoshCatty@cd25c0f`](https://github.com/binaricat/MoshCatty/commit/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04),已合并 [PR #5](https://github.com/binaricat/MoshCatty/pull/5) |
| Netcatty 配套实现 | [PR #2231 的提交 `c15b364`](https://github.com/binaricat/Netcatty/commit/c15b36412eab5d9c74a5bb5ce02294fce7fd09d5) |
| 用户问题 | [Netcatty issue #2121](https://github.com/binaricat/Netcatty/issues/2121) |
这里需要澄清“RFC 规格”的范围IETF 没有发布 Mosh 或状态同步协议 SSP 的 RFC / Internet-Draft。它的权威定义来自 [Mosh 原始论文](https://mosh.org/mosh-paper.pdf)、[官方说明](https://mosh.org/)和官方源码。Mosh 使用的 OCB3 加密算法由 [RFC 7253](https://www.rfc-editor.org/rfc/rfc7253) 定义RTT/RTO 估算参考 [RFC 6298](https://www.rfc-editor.org/rfc/rfc6298),但 Mosh 把最小 RTO 降到了 50 ms。两份 RFC 都只覆盖被 Mosh 采用的底层算法,不规定 SSP、漫游、终端同步或本地预测。
## 对照结果
### 1. SSH 启动和 `MOSH CONNECT`
官方行为:
- 官方启动器通过 SSH 启动普通用户权限的 `mosh-server`,读取端口和 128 位会话密钥,然后关闭 SSH转入 UDP。见[论文第 2 节](https://mosh.org/mosh-paper.pdf)和[`mosh.pl`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/scripts/mosh.pl#L353-L465)。
- 官方默认使用 `ssh -n -tt`,并从 `SSH_CONNECTION` 取得 SSH 实际连到的服务端地址,避免域名再次解析后把 UDP 发到另一个地址。
- 官方只接受 22 字符的 Mosh 密钥,格式由[`mosh.pl`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/scripts/mosh.pl#L415-L459)和[`crypto.cc`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/crypto/crypto.cc#L104-L153)共同限定。
当前状态:
- Netcatty PR #2231 已恢复 `-n -tt`,通过远端 POSIX `sh` 读取 `SSH_CONNECTION`,并按官方顺序把 locale 作为 `mosh-server -l` 的候选值传入,而不是强行覆盖远端 locale。见[`moshHandshake.cjs`](https://github.com/binaricat/Netcatty/blob/d2c3605bf237f211242551b1bb33dfc5ffecc5ad/electron/bridges/moshHandshake.cjs#L199-L261)。
- SSH 实际地址会优先交给 MoshCatty原始主机名作为后备候选。见[`moshSession.cjs`](https://github.com/binaricat/Netcatty/blob/d2c3605bf237f211242551b1bb33dfc5ffecc5ad/electron/bridges/terminalBridge/moshSession.cjs#L598-L639)和 MoshCatty 的[`Client::dial_candidates_with_size`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/client.rs#L147-L260)。
#2121 的意义:
`no MOSH CONNECT` 发生在 MoshCatty 启动之前。此时 Ubuntu 上看不到任何 UDP 包是符合控制流程的不是“客户端已经启动但没有发首包”。UDP 防火墙只会影响拿到 `MOSH CONNECT` 之后的阶段。
该诊断问题已经在 PR #2231 中修复:失败提示不再把“没有收到 `MOSH CONNECT`”和“检查 UDP 端口”写在一起,而是明确说明 UDP 客户端尚未启动。错误现在按阶段区分:
- SSH/服务端启动阶段没有拿到 `MOSH CONNECT`:检查 SSH 认证、PTY 输出、远端 `mosh-server` 和 locale
- MoshCatty 已启动但 15 秒内没有收到合法状态:再检查 UDP、防火墙、地址选择和 NAT。
优先级:核心启动修复为 **P0**;错误提示拆分为 **P1**
### 2. 字符重复:编号状态必须从声明的基线重建
官方行为:
SSP 的每条状态指令都声明 `old_num``new_num` 和从旧状态到新状态的 `diff`。官方接收端必须:
1. 确认 `new_num` 没有处理过;
2. 找到 `old_num` 对应的完整状态;
3. 克隆该状态并应用 `diff`
4. 按编号保存新状态,旧的乱序状态可作为以后状态的基线,但不能把当前画面倒退。
这是协议的幂等性基础,见[论文 2.2、2.3 节](https://mosh.org/mosh-paper.pdf)和官方[`networktransport-impl.h`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/network/networktransport-impl.h#L68-L174)。
高延迟下,服务端可能在收到状态 1 的确认前又发送状态 2且两者都基于状态 0。如果客户端把两个 diff 依次应用到当前画面,同一个字符就可能重复出现。
当前状态:
- MoshCatty 的传输层保留 `old_num/new_num/throwaway_num`,只接受引用仍存在基线的状态。见[`transport.rs`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/transport.rs#L581-L746)。
- 终端层按状态号保存完整画面、解析状态和回显确认;每个新状态都从它声明的旧状态克隆,再与“最新已显示状态”计算一次输出差异。见[`terminal.rs`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/terminal.rs#L178-L236)。
- 回归测试[`parallel_remote_states_render_shared_content_once`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/client.rs#L897-L918)直接覆盖了两个并行状态共享旧基线时只能显示一次的情况。
判断:最新源码中的根因已经修复;`0.1.6` 及更早版本不满足这一条件,不能继续被 Netcatty 打包。
优先级:发布并强制使用 `0.1.7+`**P0**
### 3. 本地预测回显、下划线和单一显示路径
官方行为:
- 客户端对每个按键在后台做预测,但不是所有预测都立即显示。
- 预测按 epoch 分组;一个 epoch 中任意预测被服务端证明正确后,该组其余预测才可显示。
- 可能改变回显行为的输入,如回车、部分控制键、上下方向键,会开启新的 tentative epoch。
- 一次读入超过 100 字节的批量粘贴和窗口尺寸变化会清空预测,避免把不可安全推断的大段输入或旧几何位置画到屏幕上。
- 服务端在输入交给应用至少 50 ms 后发送 `echo ack`。客户端用这个字段判断当前远端画面是否已经足以验证预测;客户端本身不使用一个简单的墙钟超时来判错。
- 高延迟下,未确认预测会带下划线;服务端确认后下划线消失。
以上机制见[论文 3.2 节](https://mosh.org/mosh-paper.pdf)、官方[`terminaloverlay.h`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/frontend/terminaloverlay.h#L179-L311)、[`terminaloverlay.cc`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/frontend/terminaloverlay.cc#L350-L873)和[`stmclient.cc`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/frontend/stmclient.cc#L275-L430)。
当前状态:
- MoshCatty 已对齐 adaptive 显示和下划线阈值、epoch、`echo_ack` 的 Pending 判定、错误预测清理、退格和左右方向键等主要规则。见[`prediction.rs`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/prediction.rs#L997-L1199)。
- 显示顺序为:重建远端 framebuffer → 验证预测 → 应用预测覆盖层 → 计算一次最终画面差异。见[`DisplayPipeline`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/prediction.rs#L1403-L1640)。
- 测试覆盖了“本地先画、远端确认后不重复”“预测字符绝不从第二条路径直接写入”“5 秒未确认时出现下划线”等场景,见[`prediction_tests.rs`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/prediction_tests.rs)。
判断:协议和内部显示路径已经对齐。剩余风险不是已知算法缺口,而是 Windows + ConPTY + xterm.js 实际组合尚未做最终视觉验收。自动测试能证明状态正确,不能完全证明用户看到的光标、下划线和字符不会被宿主终端重复处理。
优先级Windows 真实产品链路验收为 **P0**
### 4. 网络时序、重传和拥塞控制
官方行为:
- 每个 UDP 包带独立递增序列号、时间戳和可选时间戳回声;回声会扣除时间戳在对端等待发送的时间,避免 delayed ACK 污染 RTT。
- 平滑 RTT 和偏差参考 RFC 6298 的 TCP 算法,但把 RTO 限制在 501000 ms画面发送间隔约为 SRTT 的一半,并限制在 20250 ms。
- 数据 ACK 最多延迟 100 ms画面变化先收集至少 8 ms空闲时每 3 秒发送一次新编号心跳。
- 最近路径活跃时按 RTO 重传,长时间没有收到远端状态后降为每 3 秒尝试,避免断网期间持续刷包。
- ECN 拥塞标记会通过时间戳回声惩罚让对端降速。
权威实现见官方[`transportsender-impl.h`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/network/transportsender-impl.h#L49-L369)和[`network.cc`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/network/network.cc#L367-L539)。论文 2.2、2.3 节说明了相同设计目标和参数来源。
当前状态:
MoshCatty 已实现相同的 RTT 更新、501000 ms RTO、20250 ms 发送间隔、100 ms delayed ACK、8 ms 最短收集时间、3 秒心跳和长断网退避。收到乱序旧包时仍允许 SSP 使用其内容,但不会用它更新 RTT 或路径。见[`transport.rs`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/transport.rs)和[`client.rs`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/client.rs)。
判断:当前没有发现与 #2121 直接相关的剩余时序缺陷。真实公网仍需保留长期单向丢包、乱序、重复包和持续输出的压力测试,防止单元测试无法覆盖的系统 UDP 队列、调度和 NAT 行为。
优先级:持续公网压力测试为 **P1**
### 5. 漫游、断网恢复与“重连”的准确含义
官方行为:
- 客户端换 IP 或 UDP 源端口后,只要服务端收到一个认证成功且序列号更新的包,就把该包来源设为新目标。见[论文 2.2 节](https://mosh.org/mosh-paper.pdf)和官方[`network.cc`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/network/network.cc#L478-L544)。
- 客户端在 10 秒没有成功往返后更换本地 UDP 端口,旧 socket 最多保留 60 秒;这帮助 NAT 或本地路径重新建立映射。见官方[`network.cc`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/network/network.cc#L367-L400)。
- 已建立的会话默认不会因短期或长时间断网主动退出;恢复网络后继续同步最新状态。
当前状态:
MoshCatty 已实现相同的 10 秒端口跳转、旧 socket 保留、初次连接 15 秒限制、已建立会话长期等待和双向关闭握手。见[`client.rs`](https://github.com/binaricat/MoshCatty/blob/cd25c0fd1b3553d520ca3f65c93b0d3d53dffb04/src/client.rs#L27-L38)及其端口跳转、关闭处理。
需要准确区分Mosh 的“恢复”要求原来的 `mosh-client` 进程、`mosh-server` 进程和会话密钥都仍然存在。服务端长时间没有收到客户端时可以暂时清除回包目标,但进程默认继续等待;同一个客户端恢复发包后会重新附着。服务端默认等待策略见官方[`mosh-server` 手册](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/man/mosh-server.1#L95-L106)。
如果客户端进程已经退出或本机重启,新启动的官方客户端不能接管旧 `mosh-server`;如果服务端进程死亡、服务器重启或密钥丢失,也不能凭 UDP 自动复活原会话。Mosh 维护者在官方 [issue #403](https://github.com/mobile-shell/mosh/issues/403#issuecomment-15202467) 中明确说明,新客户端不能重挂旧会话,需要跨客户端进程保留任务时应配合 tmux/screen。Netcatty 此时发起的“重新连接”是重新走 SSH、创建一个新会话不是 SSP 漫游。
判断:当前实现已经具备官方 Mosh 的断网恢复和客户端漫游模型。产品说明和验收不应把“服务端死亡后自动恢复原 shell”列为 Mosh 承诺。
优先级:真实换网和 65 秒以上黑洞恢复验收为 **P0**;产品措辞澄清为 **P2**
### 6. 终端状态同步和大画面
官方行为:
- Mosh 不是传输远端输出字节流,而是服务端维护权威终端状态,客户端同步最近画面。见[论文 2、3 节](https://mosh.org/mosh-paper.pdf)和官方[`completeterminal.cc`](https://github.com/mobile-shell/mosh/blob/decd9b705eb81626f694335b8d5940538beb06da/src/statesync/completeterminal.cc#L44-L175)。
- 初始客户端状态必须带真实窗口尺寸,合法完整状态上限为 4 MiB接收端需要保留可能被后续状态引用的分支状态。
- 官方 Display 会输出足以把旧 framebuffer 变成新 framebuffer 的终端指令;宽字符、末列、擦除、滚动区、模式和光标状态都可能影响最终画面。
当前状态:
- MoshCatty 的第一个线状态已携带真实窗口尺寸;完整指令限制对齐到 4 MiB。
- 远端编号状态保存 framebuffer、解析器、显示属性和 `echo_ack`,并按 `throwaway_num` 回收。
- 最新修复补齐了宽字符续格、末列覆盖、Unicode 15 宽度差异、插入/自动换行/原点模式、滚动和光标保存恢复等行为。
判断:协议侧没有发现新的高风险缺口。仍应在目标 Windows 页面覆盖中文、emoji、窗口缩放、全屏程序、清屏重画和超过 1 MiB 的压缩画面。
还要保留一个官方 Mosh 本身的语义限制SSP 优先同步“最新屏幕状态”,不会保证像 SSH 字节流一样保存快速滚屏时的每一行历史。Mosh 原始论文在第 2 节明确指出,`cat` 大文件时依赖完整 scrollback 可能不可靠,建议使用 `less``screen``tmux`。Netcatty 把 MoshCatty 放在主屏以保留已经显示过的 scrollback但无法恢复官方服务端从未发送的中间画面。
优先级Windows 终端边界验收为 **P0**;公开说明上游 scrollback 语义为 **P2**
### 7. OCB3 与 RFC 7253
官方 Mosh 使用 AES-128 OCB3、128 位认证标签、12 字节 nonce 和空附加数据。MoshCatty 当前实现使用相同参数,并有 RFC 7253 Appendix A 测试向量、方向位、篡改拒绝和官方线格式测试。
判断:未发现与 #2121 相关的加密互通问题。RFC 7253 只能证明 OCB 算法实现,不能用来替代 SSP 和终端行为测试。
优先级:无新增工作。
## 剩余风险与优先级
| 优先级 | 项目 | 为什么仍未完成 | 可验证的完成证据 |
|---|---|---|---|
| **P0** | 合入 Netcatty PR #2231 | 当前主分支尚未强制使用新客户端,也未带 SSH 启动修复 | PR 全部检查通过并合入;正式构建实际包含新客户端 |
| **P0** | Windows 端到端验收 | #2121 的真实故障发生在 Windows跨平台单测不能替代 ConPTY 和页面显示 | 正式 Windows 包连接公网 Ubuntu完成下面的重复、预测、换网、断网、宽字符用例录屏和日志均通过 |
| **P1** | 公网 IPv6 路径 | IPv6-only、最小 MTU 和无网络分片已经通过,但本地 Mac 没有公网 IPv6 路由,仍不能替代真实跨网路径 | 从另一条公网 IPv6 前缀连接 Ubuntu 公网 IPv6完成大画面、断网和恢复后输入 |
| **P1** | Windows 长时间非对称网络压力 | Linux 隔离环境中的 30 分钟压力已经通过Windows 正式产品链路仍可能受 ConPTY、页面显示和系统网络调度影响 | Windows 正式安装包连接公网 Ubuntu在相同压力下持续 30 分钟,无漏键、重复、内存持续增长或键盘饥饿 |
| **P2** | 产品说明 | “漫游/恢复”和“重新建立新会话”容易混淆scrollback 也有上游限制 | 文档明确说明原客户端和服务端进程仍存活是恢复前提,并说明快速滚屏历史不保证完整 |
## 建议的真实复现与验收矩阵
使用用户提供的公网 Ubuntu 作为官方 `mosh-server`,本地 Netcatty/MoshCatty 作为客户端。服务端只使用 Ubuntu 官方公开安装方式和系统包,不部署修改版服务端。
1. **重复显示**:制造约 500 ms RTT连续输入 `ls`、快速重复字符、退格改字和带空格命令。页面只能显示一次,服务端逐字节收到的输入必须与键盘输入一致。
2. **预测与下划线**:分别使用 adaptive 和 `MOSH_PREDICTION_DISPLAY=always`。预测应立即出现;高延迟下未确认字符有下划线,确认后消失;不能等一个 RTT 才显示。
3. **SSH 启动**覆盖密码、公钥、带口令私钥、2FA/keyboard-interactive连续至少 100 次连接。`no MOSH CONNECT` 场景单独记录 SSH 输出,不能用“服务端无 UDP”判断 UDP 客户端故障。
4. **完全黑洞恢复**:会话建立后双向阻断 UDP 65 秒,再恢复;必须是同一远端 shell 进程、同一工作目录继续工作,客户端不能自行退出。
5. **漫游**:切换本地网络或改变 NAT/源端口;服务端收到新来源的认证包后,同一会话应在数秒内继续。
6. **单向故障**:只阻断上行、只阻断下行、只丢 ACK持续输入和持续输出检查退避、提示、端口跳转和恢复。
7. **终端同步**窗口缩放、清屏、vim/tmux、中文、emoji、宽字符落在末列、滚动区、鼠标序列和超过 1 MiB 的压缩画面。
8. **退出**:正常 `exit`、本地 `Ctrl-^ .`、网络故障后退出;服务端不应留下会话进程。
## 本次实际验证
- 在 MoshCatty `cd25c0f` 上运行 `cargo test --all-targets`**337 项通过0 项失败**4 项需要外部 SSH 凭据的 live 测试按设计跳过。
- MoshCatty PR #5 的 GitHub 检查在 Windows、macOS 和 Ubuntu 均通过4 项公网 Ubuntu live 测试连续跑了两轮,全部通过。
- 对 Ubuntu 24.04.4 官方 `mosh-server` 1.4.0 连续执行 **100 次** SSH 启动100 次都收到 `MOSH CONNECT`,并确认没有遗留服务端进程。
- `moshcatty-0.1.7` 的四个平台文件和 `SHA256SUMS` 已公开发布并全部校验通过Netcatty 的默认版本解析和本机下载都选择了 0.1.7。
- Netcatty 用正式 0.1.7 文件完成 macOS、Windows、Linux x64 和 Linux arm64 打包;本地完整结果为 **5413 项通过、0 项失败、4 项按平台跳过**,检查和生产构建通过。
- 在 Ubuntu 主机本机用 IPv6 `::1` 跑通 MoshCatty 0.1.7 与官方 mosh-server 的完整会话。测试机有公网 IPv6但本地 Mac 没有 IPv6 路由,所以公网 IPv6 路径仍未验证。
- 在独立 network namespace 中只保留 IPv6、把两端 MTU 设为 1280并发送难压缩的大画面。抓到 25 个 IPv6 UDP 包,其中服务端发出 13 个、合计 7100 字节;解密后确认同一条 Mosh 指令被拆成 6 个分片。最大 IPv6 包为 1264 字节,未出现 IPv6 Fragment Header最终画面正确。
- 在官方论文公开的 100 ms RTT、两个方向各 29% 丢包条件下完成 10 次输入;又在约 750 ms 非对称延迟、5%/12% 丢包、10%/15% 乱序和 2%/3% 重复包条件下完成 10 次输入。两组均无漏项、重复或乱序执行。
- 会话建立后双向完全断网 65 秒,并在断网期间输入命令。恢复后 10 秒内,同一会话执行了这条命令且只执行一次,随后新输入也正常完成。
- 持续 30 分钟施加约 700 ms 非对称延迟、1%/3% 丢包、5%/10% 乱序和 1%/2% 重复包;每秒输入一次,共 1800 次,每 30 秒加入一次大画面更新。最终 1800 条记录连续、无遗漏且各执行一次,解除压力后 10 秒内恢复。客户端 RSS 的 5 分钟采样为 3044、3496、3500、3500、3500、3500 KiB没有持续增长。
## 最终判断
MoshCatty 最新源码已经补齐 #2121 暴露的核心协议和预测路径当前没有证据表明需要推翻重写。字符重复的状态模型根因已经修复预测回显、下划线、长断网恢复、端口跳转、ACK/重传和终端重建也已经沿官方实现逐项对齐。
现在最重要的不是继续扩大改动,而是把已经完成的修复合入正式产品,并用 #2121 的 Windows 正式安装包 + Netcatty 页面 + 公网 Ubuntu 官方服务端拓扑做最后的人工使用验收。0.1.7 发布、连续启动、断网恢复、正式文件打包、IPv6-only 最小 MTU 和 30 分钟非对称压力都已经拿到证据;在 PR 合入、Windows 页面视觉验收和公网 IPv6 跨网路径拿到证据之前,不应关闭 #2121,也不应宣称所有环境都已完全验收。