ssh
显然,即使连接消失,人们也会尝试保留通过运行启动的进程,请参阅https://duckduckgo.com/?q=ssh+process+still+active+after+connection+close
所以我相信进程通常会因连接而终止 - 直到今天。
随机地grep
浏览ps
我机器上的输出,我发现了几周前我使用的进程ssh
,我想知道它们是如何到达那里的,现在我不知道如何不让进程保持活动状态(请参阅https://xkcd.com/2797)。
启动长时间运行的进程,例如htop
,sleep
或dmesg
作为普通用户(但任何其他用户也可以),如下所示
ssh localhost sleep 123
活下去,直到我手动杀死他们。
pstree -spc $(pgrep -f "sleep 123")
当连接仍然存在时给我
systemd(1)───sshd(1299)───sshd(1887616)───sshd(1887654)───sleep(1887655)
但是在我终止 ssh 会话(使用 CTRL-C)后,相同的命令给了我
systemd(1)───sleep(1887655)
所以对我来说,它看起来像是sshd
意识到连接已经消失,但不是终止关联的进程,而是将其移交给systemd
。
即使其他人似乎都试图实现相反的目标,我如何确保终止ssh
连接也会终止/杀死生成的进程?
注意:ssh localhost -t sleep 123
以某种方式解决了我的问题,但在我看来,因为它改变了标准输入/标准输出的处理方式。我可以告诉ssh
在连接关闭后不要移交进程吗?
sshd 从一开始就不会真正终止进程。它所做的只是在您断开连接时退出,剩余的子进程会自动获取 PID 1 作为其新父进程;您期望的自动退出是由其他东西完成的。
(此外,这并不是sshd 进行的显式切换——每当进程不再有父进程时,总会发生这种情况,并且这是自 UNIX 早期以来的标准行为。)
如果您运行交互式SSH 连接(与 tty 关联的连接),则 sshd 退出将隐式“挂起”tty 设备,这会导致操作系统自动向所有将其作为控制 tty 的进程发送 SIGHUP。大多数程序将此信号视为它们应该退出的指示。因此,这个流行工具的名字就来了
nohup
——它只需忽略 SIGHUP 就可以使程序生存。(尽管“守护进程”经常将其误用为“重新加载”信号,因此不会退出。)当您 a) 不指定任何命令并进入交互式 shell,或 b) 指定命令和选项时,就会发生上述情况
-t
。然而,使用
ssh
直接命令(并且不使用-t
)运行会禁用 tty 分配并用管道替换 stdin/stdout - 与 - 进行比较ssh myhost tty
-ssh -t myhost tty
并且管道不会执行“立即 SIGHUP”操作,这意味着没有任何内容会立即向进程发出信号退出,因此它们继续运行,操作系统只是在 PID 1 下重新设置它们的父级。当它们尝试向 stdout 写入内容并接收 SIGPIPE 时,它们最终可能会退出或被杀死(因为 stdout 管道的另一端已经被关闭),但他们可能不会。(管道在这种模式下使用是因为它们是“8 位干净”的,即从 0 到 255 的任何字节值都将不改变地通过,而 tty 设备通常执行额外的处理,这对于交互式使用很有用,但会损坏二进制数据。 )
sshd 可以使用一些机制来使子进程终止(PDEATHSIG),但据我所知,它从未使用过这些机制。
只有 systemd 才真正添加了杀死剩余进程的新机制。如果您
KillUserSomething=
在 /etc/systemd/logind.conf 中启用,它将导致 systemd 在会话结束时故意杀死所有内容(或者当用户不再有会话时;我不记得了)。有些发行版默认启用此功能,而其他发行版则不启用。systemd 机制通过 PAM“会话”机制工作,当 sshd 在退出之前调用“关闭会话”时(pam_systemd 也有一种方法来检测进程何时终止)并杀死由 systemd-logind 管理的cgroup中的所有内容。