连接关闭时如何远程终止称为“tail -f”?

Dmi*_*ank 24 process ssh terminal signals

我只是注意到,如果我执行ssh user@remote_host tail -f /some/filetail -f /some/file即使 ssh 连接关闭,它也会继续在 remote_host 上运行!

因此,经过多次连接和断开连接后,运行的次数会tail -f /some/file增加。tail -fssh 连接关闭时如何实际终止?

Sté*_*las 33

ssh host tail -f file
Run Code Online (Sandbox Code Playgroud)

ssh客户端连接到sshd服务器上host通过TCP连接。sshd运行tail -f时将其标准输出重定向到管道。sshd读取来自管道另一端的内容并将其封装在 sshd 协议中以发送给ssh客户端。(使用rshdtailstdout 将直接作为套接字,但sshd添加了加密并能够在单个 TCP 连接上多路复用多个流(如端口/代理/X11/隧道重定向、stderr),因此必须求助于管道)。

当您按下 CTRL-C 时,一个 SIGINT 被发送到ssh客户端。这导致ssh死亡。在死亡时,TCP 连接关闭。因此,在hostsshd也会死亡。tail没有被杀死,但它的标准输出现在是另一端没有读取器的管道。因此,下次它向其标准输出写入内容时,它将收到一个 SIGPIPE 并死亡。

在:

ssh -t host 'tail -f file'
Run Code Online (Sandbox Code Playgroud)

这是相同的东西,只是用与管道之中,之间的通信sshd,并tail是经由一伪终端。tail的 stdout 是一个从属伪终端(如/dev/pts/12),并且在主端(可能由 tty 行规则修改)tail写入的任何内容read都由sshd并封装到ssh客户端发送。

在客户端侧,具有-tssh把终端raw模式。特别是,这会禁用终端规范模式和终端信号处理。

因此,当您按下 时Ctrl+C,不是客户端的终端线路规则向ssh作业发送 SIGINT ,而是通过^C连接将字符发送到远程终端的主端sshd并将其sshd写入^C。并且远程终端的线路规则发送SIGINTtail. tail然后死掉,sshd退出并关闭连接并ssh终止(如果它不是还在忙于端口转发或其他)。

此外,使用-t,如果ssh客户端死亡(例如,如果您输入~.),则连接将关闭并sshd死亡。结果,一个 SIGHUP 将被发送到tail.

现在,请注意使用-t有副作用。例如,使用默认的终端设置,\n字符被转换为\r\n并且可能会发生更多的事情取决于远程系统,因此stty -opost如果该输出不用于远程主机,您可能希望在远程主机上发出(以禁用输出后处理)一个终端:

$ ssh  localhost 'echo x' | hd
00000000  78 0a                                             |x.|
00000002
$ ssh -t localhost 'echo x' | hd
00000000  78 0d 0a                                          |x..|
00000003
$ ssh -t localhost 'stty -opost; echo x' | hd
00000000  78 0a                                             |x.|
00000002
Run Code Online (Sandbox Code Playgroud)

使用-t/ 的另一个缺点-tt是 stdout 和 stderr 在客户端没有区别。远程命令的 stdout 和 stderr 都将写入ssh客户端的 stdout:

$ ssh localhost ls /x  | wc -l
ls: cannot access /x: No such file or directory
0
$ ssh -t localhost ls /x | wc -l
1
Run Code Online (Sandbox Code Playgroud)


Hau*_*ing 11

您需要在远程端分配终端:

ssh -t user@remote_host tail -f /some/file
Run Code Online (Sandbox Code Playgroud)

甚至

ssh -tt user@remote_host tail -f /some/file
Run Code Online (Sandbox Code Playgroud)

  • @DmitryFrank 你误解了这个问题。问题是**不是**`tail`不会对`SIGHUP`做出反应。问题是在没有伪终端的情况下,`SIGHUP` **not sent` 到 `tail`。在这两种情况下,您都可以通过将 `strace` 附加到 `tail` 来看到这一点。 (3认同)
  • @DmitryFrank 我的理解是:如果连接中断,则`sshd` 会发送一个`SIGHUP`。但是在没有终端的地方不能有终端连接挂断...... (2认同)