rsync
或cp
或任何其他可以长时间运行的命令后,就断开了与SSH会话的连接。在断开连接后该命令会一直运行直到完成,还是被杀死?总是想知道这一点。
#1 楼
编辑2016年:此问答早于systemd v230故障。从systemd v230开始,新的默认设置是杀死终止登录会话的所有子级,无论采取了什么历史上有效的预防措施来防止这种情况。可以通过在
KillUserProcesses=no
中设置/etc/systemd/logind.conf
来更改行为,或者使用在用户空间中启动守护程序的特定于systemd的机制来规避该行为。这些机制超出了这个问题的范围。下面的文字描述了传统上事物在UNIX设计空间中的工作时间比Linux更长。
它们将被杀死,但不一定立即被杀死。这取决于SSH守护程序确定连接已失效所需的时间。下面是一个更长的解释,可以帮助您了解它的实际工作原理。
登录后,SSH守护程序为您分配了一个伪终端,并将其附加到用户配置的登录Shell中。这称为控制终端。到那时,正常启动的每个程序,无论外壳层有多深,最终都可以将其祖先追溯到该外壳。您可以使用
pstree
命令观察到此情况。当与您的连接关联的SSH守护进程确定您的连接已死时,它将挂断信号(
SIGHUP
)发送到登录外壳。这会通知您已消失的外壳,并且外壳应自行清理。此时发生的事情是特定于shell的(在其文档页面上搜索“ HUP”),但是在大多数情况下,它将开始向与之关联的正在运行的作业发送SIGHUP
,然后终止。这些进程中的每个进程继而将在接收到该信号后执行它们配置为执行的任何操作。通常这意味着终止。如果这些工作都有自己的工作,那么信号也会经常传递出去。在控制终端挂断后幸存下来的进程要么是使自己脱离拥有终端的进程(您在终端内部启动的守护进程),要么是通过前缀
nohup
命令调用的进程。 (即“不要挂断”)守护程序以不同的方式解释HUP信号;由于它们没有控制终端,并且不会自动接收HUP信号,因此,管理员将其重新用作手动请求以重新加载配置。具有讽刺意味的是,这意味着大多数管理员要等到很久以后才了解非守护程序对该信号的“挂断”用法。这就是为什么要阅读这篇文章!端子多路复用器是在断开连接之间保持外壳环境完整的一种常用方法。它们使您能够以某种方式从Shell进程中分离出来,以便以后可以重新连接到它们,而无论断开是偶然还是有意进行的。
tmux
和screen
是最受欢迎的;使用它们的语法超出了您的问题范围,但是值得研究。我要求详细说明SSH守护程序确定该请求所花费的时间。您的连接已死。这是特定于SSH守护程序的每种实现的一种行为,但是您可以指望当双方重置TCP连接时,它们全部终止。如果服务器尝试写入套接字且未确认TCP数据包,则将很快发生这种情况;如果没有尝试写入PTY的情况,则将发生这种情况。
在这种特定情况下,最可能的因素是触发写操作的是:试图写到服务器端PTY的进程(通常是前台的进程)。 (服务器->客户端)
用户尝试在客户端上写入PTY。 (客户端->服务器)
任何形式的Keepalive。默认情况下,客户端或服务器通常不会启用这些功能,通常有两种形式:应用程序级别和基于TCP的版本(即
SO_KEEPALIVE
)。即使当没有其他理由没有理由向套接字写入消息时,Keepalive很少会向服务器或客户端发送数据包到另一端。虽然这通常是为了避免防火墙过快地使连接超时,但它具有附加的副作用,当另一端的响应速度没有那么快时,它会使发送者注意到。通常TCP会话规则适用于此:如果客户端和服务器之间的连接中断,但在出现问题期间双方均未尝试发送数据包,则只要双方随后做出响应并接收到预期的TCP序列号,连接将继续存在。
如果一方确定套接字已死,则效果通常是立竿见影的:sshd进程将发送
HUP
并自行终止(如前所述),否则客户端将通知用户检测到的问题。值得注意的是,仅因为一方认为另一方已死并不意味着已通知另一方。连接的孤立端通常将保持打开状态,直到它尝试对其进行写操作并超时,或者从另一端收到TCP重置。 (如果当时连接可用)仅在服务器注意到后,才进行此答案中描述的清理。评论
我还要在该列表中添加“ dtach”命令-它与screen / tmux相反,它可以让您将多个终端连接到一个会话,并且对于延长会话时间也很有用,尽管它不会提供任何重放最近历史的方法。
–蓬松
2013年1月6日17:10
dtach网址在这里:dtach.sourceforge.net
–slm
13年1月6日在20:17
极好的解释。我已经感觉更多了linuxey!
–煤气
13年1月7日在22:31
另外,尽管从技术上讲,这不是您的答案的一部分,但这里有一些有趣的琐事:您可以使用kill -HUP作为根目录来强制某人的终端挂断。没有正当理由,您不应该这样做。当用户在维护期间让Shell运行时,我大部分精力都花在了上面,我需要卸载一个文件系统,使他们的Shell保持打开状态。如果用户已连接但最终空闲,则将信号发送到他们的sshd进程。否则,如果它在终端多路复用器内部运行,请将其发送到您要停止的外壳程序。只挂壳,让您无法工作!
–安德鲁(Andrew B)
2013年1月7日23:36
@AndrewB,能否请您详细说明“ SSH守护进程...如何确定您的连接已死”?以及我怎么知道SSH守护进程是否认为/知道(哪个)连接已死?
– ZenUML.com上的Peng
16-4-11的2:02
#2 楼
正如其他人提到的那样,一旦与ssh断开连接,其中运行的任何内容都将消失。@Michael Hampton和其他人提到,您可以使用
tmux
或screen
之类的工具来断开/重新连接到终端,而不会松动它们内容(即子进程)。另外,您可以使用&号
&
将进程置于后台,然后使用命令disown
将其与当前外壳解除关联。# 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
%
评论
是否可以将终端会话重新附加到一个无用的进程?
–假名
13年1月6日在7:25
是。有关详细信息,请参见此U&L问题:unix.stackexchange.com/questions/4034/…
–slm
13年1月6日在7:33
#3 楼
不,任何仍附加在终端上且未放置在诸如nohup
之类的后台程序都将被杀死。这就是为什么存在诸如
tmux
和较旧的screen
之类的虚拟终端解决方案会创建会话的原因即使断开连接,它们仍然可以继续运行,以后可以重新连接。
评论
我只是想补充一下以上内容,如果您发现自己需要将已经在运行的进程放到屏幕上的情况,请尝试reptyr。它将杀死您的程序。如果要通过SSH将操作系统版本从Ubuntu 16.04更新到17.10,则非常烦人。