题 与SSH会话断开连接是否会导致您的程序失效?


所以,说我在开始之后断开了与SSH会话的连接 rsync 要么 cp 或任何其他可以长时间运行的命令。该命令是否会一直运行,直到我断开连接或它刚被杀后才能运行?

总是想知道这一点。


75
2018-01-06 03:09




我只想补充上面所说的,如果你发现自己处于需要将已经运行的流程放入 screen,试试 reptyr。 - a sad dude


答案:


编辑2016年:

这个Q&A早于 systemd v230崩溃。从systemd v230开始,新的默认设置是终止终止登录会话的所有子节点,无论采取了哪些历史上有效的预防措施来防止这种情况。可以通过设置更改行为 KillUserProcesses=no 在 /etc/systemd/logind.conf,或使用特定于systemd的机制规避在用户空间中启动守护程序。这些机制超出了这个问题的范围。

下面的文本描述了传统上在UNIX设计空间中工作的时间比Linux已经存在的时间长。


他们会被杀死,但不一定立即被杀死。这取决于SSH守护程序确定您的连接已停止所需的时间。以下是一个较长的解释,将帮助您了解它的实际工作原理。

登录时,SSH守护程序为您分配了一个伪终端,并将其附加到用户配置的登录shell。这称为控制终端。你在那个时候正常开始的每一个程序,无论多少层太深,最终都会将它的祖先追溯到那个外壳。你可以用这个来观察 pstree 命令。

当与您的连接关联的SSH守护进程确定您的连接已死时,它会发送挂断信号(SIGHUP)到登录shell。这通知shell你已经消失了它应该开始清理它自己。此时发生的是特定于shell的(在其文档页面中搜索“HUP”),但大多数情况下它将开始发送 SIGHUP 在终止之前运行与之关联的作业。反过来,这些过程中的每一个都将执行它们在接收到该信号时配置的任何操作。通常这意味着终止。如果这些工作有自己的工作,信号也会经常传递。

在控制终端挂断后仍然存在的进程要么与自己的终端(你在其中启动的守护程序进程)取消关联,要么使用带前缀调用的进程 nohup 命令。 (即“不要挂断”)守护进程以不同的方式解释HUP信号;因为它们没有控制终端并且不自动接收HUP信号,所以它被重新用作管理员的手动请求以重新加载配置。具有讽刺意味的是,这意味着大多数管理员都不会为非守护进程学习这种信号的“挂断”使用,直到很久以后。这就是你读这个的原因!

终端多路复用器是在断开连接之间保持shell环境完整的常用方法。它们允许您以稍后可以重新连接到它们的方式从shell进程中分离,无论该断开是偶然还是故意。 tmuxscreen 是更受欢迎的;使用它们的语法超出了你的问题的范围,但它们值得研究。


有人请求我详细说明SSH守护进程需要多长时间才能确定您的连接已经死亡。这是一种特定于SSH守护程序的每个实现的行为,但是当任何一方重置TCP连接时,您可以指望所有这些行为终止。如果服务器尝试写入套接字并且TCP数据包未被确认,则会很快发生,如果没有尝试写入PTY,则会缓慢发生。

在这个特定的上下文中,最有可能触发写入的因素是:

  • 尝试写入服务器端PTY的进程(通常是前台进程)。 (服务器 - >客户端)
  • 用户尝试在客户端写入PTY。 (客户端 - >服务器)
  • 任何类型的Keepalive。默认情况下,这些通常不是由客户端或服务器启用的,通常有两种风格:应用程序级别和基于TCP的(即 SO_KEEPALIVE)。 Keepalive相当于服务器或客户端不经常向另一端发送数据包,即使没有任何理由可以写入套接字。虽然这通常是为了避免过快地连接超时的防火墙,但它具有额外的副作用,即当另一方没有更快地响应时发送者注意到。

TCP会话的通常规则适用于此:如果客户端和服务器之间的连接中断,但在问题期间双方都没有尝试发送数据包,则连接将继续存在,前提是双方都在事后响应并接收到预期的TCP序号。

如果一方已确定套接字已死,则效果通常是立即的:sshd进程将发送 HUP 并自行终止(如前所述),或者客户端将通知用户检测到的问题。值得注意的是,仅仅因为一方认为另一方已经死亡并不意味着另一方已被通知此事。连接的孤立端通常将保持打开状态,直到它尝试写入并超时,或从另一端接收TCP重置。 (如果当时连接可用)此答案中描述的清理只发生一次 服务器 注意到了。


108
2018-01-06 04:36



我还将'dtach'命令添加到该列表中 - 它与screen / tmux相反,它允许您将多个终端连接到单个会话,并且也非常适合延长会话,尽管它不会提供重播近期历史的任何方法。 - fluffy
dtach 网址在这里: dtach.sourceforge.net - slm
优秀的解释。我已经感觉更加柔美了! - fregas
此外,虽然从技术上讲,这不是你的答案的一部分,但这是一个有趣的琐事:你可以使用 kill -HUP 以root身份迫使某人的终端挂机。没有充分理由你不应该这样做。当用户在维护期间保持shell运行时,我得到了大部分时间,我需要卸载他们的shell保持打开的文件系统。如果用户已连接但终端空闲,则将信号发送到其sshd进程。否则,如果它在终端多路复用器内运行,则将其发送到您想要停止的shell。只挂机壳让你无法工作! - Andrew B
@AndrewB,您能否详细说明“SSH守护进程如何...决定您的连接已经死亡”?我怎么知道SSH守护进程是否认为/知道(哪个)连接已经死了? - Xiao Peng - ZenUML.com


正如其他人所提到的那样,一旦你从ssh断开连接,它内部的任何东西都会消失。

@Michael Hampton 和其他人提到你可以使用像 tmux 要么 screen 断开/重新连接到终端而不丢失其内容(即子进程)。

此外,您可以使用&符号将进程放入后台 & 然后使用该命令 disown 将它们与当前的shell解除关联。

# start a command
% sleep 5000 &
[1] 3820

# check it
% jobs
[1]+  Running                 sleep 5000 &

# disown everything
% disown -a

# check it again (gone from shell)
% jobs
%

# but it's still running on the system
% ps -eaf|grep "[s]leep"
saml      3820 23791  0 00:16 pts/1    00:00:00 sleep 5000
%

21
2018-01-06 05:27



是否可以将终端会话重新连接到 disowned过程? - Fake Name
是。有关详细信息,请参阅此U&L问题: unix.stackexchange.com/questions/4034/... - slm


不,任何程序仍然附加到终端,而不是像背景那样放在后台 nohup,会被杀死。

这就是为什么有像这样的虚拟终端解决方案 tmux 和年长的 screen 即使断开连接也会创建继续运行的会话,以后可以重新连接。


11
2018-01-06 03:16