这类会话在编辑器启动时保持连接,随后即使 SSH 进程明显还活着,屏幕也不再刷新。按键没有任何输出,Ctrl-C 似乎不起作用,于是很容易断定是 VPN 丢了什么。多数情况下隧道没问题,是远端伪终端处在没人想要的状态,因为回显、规范输入和流控住在终端里,而不在网络里。弄清这三者中哪一个变了,只需两条命令。

卡顿在终端里,不在隧道里

伪终端承载的不只是字节。它保存线路规程标志,决定输入是否回显、读取是否等待换行、某些字符是否产生信号,以及输出能否被控制字符暂停。交互式编辑器会在整个运行期间把该终端切到原始模式,并应在退出时恢复之前的设置。如果没有恢复,你回到的 shell 就不再是你离开的那个 shell,即使连接从未断开。

在下任何结论之前,先比较终端。第二个会话跑同一个编辑器,只能证明客户端和路径能干活;它对标志损坏的那个终端什么也说明不了。

读一读冻结那个终端的设置

先确定设备,再读取它状态的两种形式。可读形式显示设了什么,机器形式则是之后能回灌的那份。

tty
stty -a
stty -g

三组标志解释了其中大部分报告。回显设置决定按键是否显示,所以关掉回显的终端看起来像死了,而 shell 其实收到了每个字符。规范模式决定程序是否按行接收输入,所以留在规范模式的终端会让原始模式程序看起来直到按 Enter 才理会按键。流控设置决定终端是否响应 XON 和 XOFF 字符,而这一组正是三者中最像真卡死的假象来源。

改任何东西之前先记录输出,尤其是会话带有别人依赖的自定义键绑定时。机器形式是最安全的记录,但要注意它依赖具体实现,应由产生它的同类系统来恢复。

修复那一个终端,而不是你正在输入的会话

标准修复会恢复手册页列出的 sane 配置,而且只影响一个终端。如果编辑器在那个终端里还有未保存的工作,就先别动,等存好再说。

从另一个 shell 明确指定那个冻结的设备,这样你正在使用的终端就不会被动到。

stty -F /dev/pts/7 -a
stty -F /dev/pts/7 sane

显示损坏的空屏与线路规程损坏是两回事,reset 程序通过发送终端初始化序列来处理它。先试状态修复,因为它改的是你能检查的设置;而 reset 序列会重写屏幕,却说不清它是怎么坏的。

一场逼真卡死背后的 Ctrl-S 陷阱

当软件流控开启并分配了常用字符时,Ctrl-S 让终端暂停发送输出,Ctrl-Q 让它继续。会话全程都活着,一次 Ctrl-Q 往往就是全部修复,而且任何日志里都不会有记录,这就是它能躲过那么多次升级排查的原因。

去检查实际设置,而不是假设。启停字符可以被重新分配或禁用,而流控关掉的终端对两者都不会有反应。

如果状态反复出现,或者 SSH 本身卡顿

反复出现的坏状态说明有东西改了标志却没恢复:启动文件、包装脚本、重置错窗口的复用器,或者持有原始模式时崩溃的程序。加上会报告状态的条件检查,而不是无条件重置,因为一刀切的重置会掩盖原因,还可能覆盖有意的设置。

当普通 SSH 流量也卡住,或修复毫无变化时,终端就不再是嫌疑对象。

ssh -vvv [email protected]
ping -M do -s 1400 -c 3 host.example.com

只在大文件传输时出现卡顿,提示路径 MTU 有问题;连单次按键都被吞掉,则指向路径或服务器,而不是包大小。把终端证据和网络证据分开看,因为第二个会话里编辑器能用,并不能证明第一个终端曾经健康。

相关文章