与 SSH 会话断开连接会杀死您的程序吗?

fre*_*gas 100 linux ssh systemd

所以,说我从一个SSH会话断开连接,我已经开始之后rsynccp或其他任何命令,可以是长期运行。在我断开连接后,该命令会一直运行直到完成还是只是被杀死?

一直想知道这个。

And*_*w B 125

2016年编辑:

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

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


他们会被杀死,但不一定立即被杀死。这取决于 SSH 守护程序需要多长时间才能确定您的连接已失效。下面是一个更长的解释,将帮助您了解它的实际工作原理。

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

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

在控制终端挂断后幸存下来的进程要么与终端(您在其中启动的守护进程)脱离关联,要么使用前缀nohup命令调用的进程。(即“不要挂断这个”)守护进程以不同的方式解释 HUP 信号;由于它们没有控制终端并且不会自动接收 HUP 信号,因此它被重新用作管理员手动请求重新加载配置。具有讽刺意味的是,这意味着大多数管理员直到很久以后才了解非守护进程的此信号的“挂断”用法。这就是为什么你要读这个!

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


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

在这种特殊情况下,最有可能触发写入的因素是:

  • 尝试写入服务器端 PTY 的进程(通常是前台进程)。(服务器->客户端)
  • 尝试在客户端写入 PTY 的用户。(客户端->服务器)
  • 任何种类的保活。这些通常不被客户端或服务器默认启用,并且通常有两种风格:应用程序级别和基于 TCP 的(即SO_KEEPALIVE)。Keepalives 相当于服务器或客户端不经常向另一端发送数据包,即使没有其他原因可以写入套接字。虽然这通常是为了绕过连接过快超时的防火墙,但它具有额外的副作用,即当另一方没有更快响应时,会导致发送方注意到。

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

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

  • 我还将“dtach”命令添加到该列表中 - 它与 screen/tmux 有点相反,因为它允许您将多个终端连接到单个会话,并且也非常适合延长会话,尽管它没有提供任何重播最近历史的方法。 (3认同)
  • 此外,虽然从技术上讲这不是您的答案的一部分,但这里有一个有趣的琐事:您可以使用 `kill -HUP` 作为 root 来强制某人的终端挂断。你不应该没有充分的理由这样做。当用户在维护期间让 shell 运行时,我获得了大部分的收益,我需要卸载一个他们的 shell 保持打开状态的文件系统。如果用户已连接但终端空闲,则将信号发送到他们的 sshd 进程。否则,如果它在终端多路复用器内运行,请将其发送到您想要停止的外壳程序。只挂起外壳,让您无法工作! (3认同)
  • 很好的解释。我已经感觉更 linuxey 了! (2认同)

slm*_*slm 24

正如其他人所提到的,一旦您与 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
%
Run Code Online (Sandbox Code Playgroud)

  • 是的。有关详细信息,请参阅此 U&L 问题:http://unix.stackexchange.com/questions/4034/how-can-i-disown-a-running-process-and-associate-it-to-a-new-screen-shell (4认同)

Mic*_*ton 15

不,任何仍然连接到终端的程序,并且没有像 那样放在后台nohup,都会被杀死。

这就是为什么有虚拟终端解决方案tmux和更旧的解决方案,screen它们创建的会话即使断开连接也继续运行,并且您可以稍后重新连接。