为什么在SSH连接中断时控制台有时会永远挂起?


89

我已经在许多控制台(在Linux,Mac上,...)以及许多不同网络中的许多不同机器上看到了这一点。我永远无法查明发生这种情况的确切原因:您要做的就是通过SSH登录到计算机。如果连接由于某种原因而中断(为简单起见,假设网络电缆被拔出),则有时控制台会永远挂起-在其他时候,它对父shell的出口也很好。

发生这种情况时非常烦人(例如,您丢失了命令历史记录。)也许存在秘密的键盘快捷键可以强制退出(Ctrl-C或Ctrl-D无效)?而且,在所有实现中产生此随机“错误”的原因是什么?


提到Mosh(移动Shell)似乎很合适,它可以很好地处理连接失败,包括漫游(更改IP)和其他问题。
CiprianTomoiagă17年

Answers:


137

有一个“秘密”键盘快捷键可以强制退出:〜)在冻结的会话中,按以下顺序敲击这些键:Enter~.代字号(仅在换行符之后)被ssh客户端识别为转义序列,并且句点告诉客户终止交易无需再费力。

在通信问题上长期存在的行为不是错误,SSH会话正在进行中,希望另一端能够回来。如果网络中断,有时甚至几天后,您就可以恢复SSH会话。当然,您可以明确地告诉它放弃并死于上述顺序。您还可以执行多种操作,例如在客户端中设置保持活动超时,这样,如果客户端在一定时间内没有活动链接,它将自行关闭,但默认行为是保持为尽可能连接!

编辑:此中断密钥的另一个有用的应用是引起本地ssh客户端的注意,并使其后台运行一分钟回到本地shell(例如,从您的历史记录中获取一些信息),然后将其搁置以继续远程工作。Enter~ Ctrl+ Z将ssh客户端发送到本地shell的后台作业队列,然后fg像往常一样将其取回。

编辑:处理嵌套的SSH会话时,可以添加多个波浪号字符以仅中断链中的SSH会话之一,而保留其他会话。例如,如果您嵌套在3个级别中(例如,从local-> Machine1-> Machine2-> Machine3使用ssh),Enter~.将使您回到本地会话,Enter~~.将您留在Machine1中,并将Enter~~~.您留在Machine2中。这也适用于其他转义序列,例如将ssh会话临时移至后台。上面的方法适用于任何级别的嵌套,只需添加更多代字号即可。

最后,您可以使用Enter~?来打印可用转义命令的帮助菜单。

TL; DR-受支持的转义命令是受支持的转义序列:

 ~.   - terminate connection (and any multiplexed sessions)
 ~B   - send a BREAK to the remote system
 ~C   - open a command line
 ~R   - request rekey
 ~V/v - decrease/increase verbosity (LogLevel)
 ~^Z  - suspend ssh
 ~#   - list forwarded connections
 ~&   - background ssh (when waiting for connections to terminate)
 ~?   - this message
 ~~   - send the escape character by typing it twice
(Note that escapes are only recognized immediately after newline.)

11
+1表示知道在头部射击sshd的十二度秘密机密密码。您是否以与我相同的方式找到它(按~/.somethingorotherEnter 键后输入错误)?
voretaq7 2011年

2
@ voretaq7:不,我不是那么聪明,但是当有人向我提示时,我说:“真的吗?这就是我的shell刚砰的时候发生的一切!” 。除了您提到的错误类型以外,这不是一个常见的序列,但是它可能发生。
Caleb

14
其中“秘密”的意思是“在手册页中”。
larsks 2011年

4
尽管许多人对此一无所知,但从实际情况看,这确实是一个秘密。man ssh在本ESCAPE CHARACTERS节下涵盖此内容。~.(断开连接)和~^Z(背景ssh)非常方便。
Stefan Lasiewski 2011年

9
当然,它在手册页中:)我只用了secret一词,因为OP用过了,而且我在脸颊上用了舌头。此功能的问题在于,人们不知道在哪里寻找它,他们期望控制字符和此类信号成为外壳等的一部分。一旦您知道在哪里看甚至要问什么,当然就在那里。
Caleb

12

SSH提供了保持活动的功能。将以下内容添加到本地~/.ssh/config(如果不存在则创建):

ServerAliveInterval 15
ServerAliveCount 3

此设置将建立一个每15秒通过安全隧道发送一次的保持活动信号。连续三个失败后,SSH客户端将退出。

请注意,在某些系统(包括macOS 10.14)上,它需要是:

ServerAliveInterval 15
ServerAliveCountMax 3

从ask.ubuntu上的此答案中获取:https ://askubuntu.com/a/29967/30266


9

它挂起的事实是TCP的功能,而不是SSH。除非TCP使用连接通知应用程序该连接不再存在,否则该应用程序无法知道TCP会话/连接已断开。从每个主机的角度来看,TCP会话仍处于“已建立”状态,无话可说,长时间的空闲(无数据流)会话除了RST或对TCP Keepalive数据包没有响应(这是无效的)外都是无效的。尚未普遍实施)。对我来说,这似乎不是SSH中的错误,我希望这种行为。


5

如果连接正确挂起,则任何魔术按键都不会通过,因为在您发出按键之前连接已经挂起。您可以告诉客户端终止,但这不会影响在服务器端保留(或不保留)的历史记录。

虽然这实际上不能回答问题,但它可能有助于减少连接挂起的影响:当我在远程工作时(甚至通常在我不在时),我会进行遍历screenbyobu根据其可用性使用或不使用包装器)这样,如果有任何连接中断,我的会话及其所有历史记录都将保留并以我重新连接时离开它的状态可用。


6
您关于屏幕的建议很好,但实际上第一点不适用于此问题。您不需要将密钥传递到远程端,只需要将它们传递到LOCAL ssh客户端!OP希望返回包括历史在内的本地信息。SSH接管了它,并且不响应CTRL-C之类的常规中断序列,因为它传递了这些序列。有一种方法可以打通并终止本地客户端,请参见我的回答。如果再次登录,通常会保留本地端的历史记录,具体取决于shell配置。
Caleb

2
@Caleb:该问题专门提到了丢失历史记录,命令历史记录存储在服务器端。要告诉服务器对历史记录执行不同的操作,您需要向服务器发送一条消息,告诉服务器对历史记录执行不同的操作。当然,有一些方法可以使bash(和一些其他shell)立即记录历史记录行,而不是将它们收集在RAM中,直到用户使用exit/ 正确存在该shell为止,logout这将解决历史记录问题而无需使用screen
David Spillett
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.