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

Chr*_*her 114 networking ssh console connection

我已经在许多控制台(在 Linux、Mac 上……)以及许多不同网络中的许多不同机器上看到了这一点。我永远无法确定发生这种情况的确切原因:您所要做的就是通过 SSH 登录到一台机器。如果由于某种原因连接中断(为简单起见,假设网络电缆被拉出),那么有时控制台会永远挂起 - 在其他时候,它只是正常退出到父 shell。

发生这种情况时很烦人(例如,您丢失了命令历史记录。)是否有可以强制退出的秘密键盘快捷键(Ctrl-C 或 Ctrl-D 不起作用)?无论如何,所有实现中出现这个随机“错误”的原因是什么?

Cal*_*leb 184

有一个“秘密”键盘快捷键可以强制退出 :~) 从冻结的会话中,按顺序按下这些键:Enter~.波浪号(仅在换行符之后)被 ssh 客户端识别为转义序列,句点告诉客户立即终止其业务。

通信问题上的长时间挂起行为不是错误,SSH 会话挂起希望对方回来。如果网络中断,有时甚至几天后您就可以恢复 SSH 会话。当然你可以具体告诉它放弃,按照上面的顺序死掉。您还可以执行多种操作,例如在客户端中设置保持活动超时,以便在一段时间内没有活动链接时,它会自行关闭,但默认行为是保持不变尽可能连接!

编辑:这个中断键的另一个有用的应用是引起本地 ssh 客户端的注意,并将其作为后台返回到本地 shell 一分钟——比如从你的历史记录中获取一些东西——然后将其转发以继续远程工作。Enter~ Ctrl+Z将 ssh 客户端发送到本地 shell 的后台作业队列,然后fg像往常一样将其取回。

编辑:在处理嵌套的 SSH 会话时,您可以添加多个波浪号字符以仅中断链中的一个 SSH 会话,但保留其他会话。例如,如果您嵌套在 3 个级别(即您从Enter~.本地- >机器 1->机器 2->机器 3 进行 ssh),将使您返回本地会话,Enter~~.将您Enter~~~.留在机器1 中,并将您留在机器 2 中. 这也适用于其他转义序列,例如将 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.)
Run Code Online (Sandbox Code Playgroud)

  • 其中“秘密”的意思是“在手册页中”。 (20认同)
  • +1 知道用于在头部射击 sshd 的 dodecatouple-secret-probation 密码。你有没有像我一样发现它(按回车键后输入错误`~/.somethingorother`)? (11认同)
  • 当然,它在手册页中 :) 我只使用了秘密这个词,因为 OP 这样做了,而且我在脸颊上使用舌头。此功能的问题在于人们不知道在哪里寻找它,他们希望控制字符和此类信号成为 shell 等的一部分。一旦你知道去哪里寻找,甚至知道要问什么,它当然就在那里。 (9认同)
  • @voretaq7:不,我没那么聪明,但是当有人给我提供线索时,我去*“真的吗?所以这就是发生的所有那些时候,我的外壳在我打字时无缘无故地爆炸了?”*。除了您提到的错误类型之外,这不是一个常见的序列,但它可能会发生。 (4认同)
  • 虽然很多人不知道这件事,但它确实是一个显而易见的秘密。`man ssh` 在 `ESCAPE CHARACTERS` 部分涵盖了这一点。`~.`(断开连接)和`~^Z`(后台ssh)非常方便。 (4认同)

krl*_*mlr 17

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

ServerAliveInterval 15
ServerAliveCount 3
Run Code Online (Sandbox Code Playgroud)

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

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

ServerAliveInterval 15
ServerAliveCountMax 3
Run Code Online (Sandbox Code Playgroud)

取自 ask.ubuntu 上的这个答案:https ://askubuntu.com/a/29967/30266


joe*_*rty 9

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


Dav*_*ett 5

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

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

  • 您对 screen 的建议很好,但第一个实际上不适用于该问题。您不需要将密钥传递到远程端,只需将它们传递到 LOCAL ssh 客户端即可!OP想要的是他的本地外壳,包括历史。SSH 接管它并且不会响应像 CTRL-C 这样的正常中断序列,因为它会传递这些序列。有一种方法可以通过并终止本地客户端,请参阅我的答案。如果您再次登录,通常会保留本地端的历史记录,具体取决于 shell 配置。 (6认同)
  • @Caleb:问题特别提到了丢失历史记录,并且命令历史记录存储在服务器端。要告诉服务器对历史做任何不同的事情,您需要向服务器发送一条消息,告诉它对历史做一些不同的事情。当然,有一些方法可以让 bash(和其他一些 shell)立即记录历史行,而不是将它们收集在 RAM 中,直到用户使用 `exit`/`logout` 正确存在 shell,这将在不使用 `screen` 的情况下解决历史问题. (2认同)