【问题标题】:Get the TTY which sent a signal in Perl获取在 Perl 中发送信号的 TTY
【发布时间】:2012-06-28 15:55:42
【问题描述】:

我有一个 Perl 脚本,它作为电子邮件服务器上的后台进程运行,并尝试通过对队列和日志文件的各种检查来检测受损的电子邮件帐户。我为 USR1 信号添加了一个处理程序,它使脚本在运行时打印一些关于它自己的信息。如果我在后台启动脚本然后发送 USR1 信号,这将非常有用,如下所示:

./myscript.pl & 杀死-USR1(PID)

问题是,如果我退出该 shell 会话,然后再次连接,当我使用 kill -USR1 命令时将无法获得任何输出,因为与脚本的 STDOUT 关联的 TTY 已消失。

所以,我想知道是否有办法获取在 Perl 中发送信号的用户或 shell 进程的 TTY,然后直接输出回 TTY 而不是 STDOUT。我尝试在信号处理程序中使用POSIX::ttyname(1),但它返回脚本的 STDOUT 的 TTY(在本例中为空值),而不是发送 USR1 信号的用户的 TTY。

我在 POSIX 的 Perldoc 中看到 POSIX::sigaction 将给出生成信号的进程的 PID 和 UID,但我不知道是否有一种从 Perl 中的信息中获取 TTY 名称的好方法。

任何帮助将不胜感激!谢谢!

【问题讨论】:

  • 为什么不使用某种日志文件来捕获脚本的输出:./myscript.pl > some.log &,然后在您喜欢的任何 TTY 上使用tail -f some.log 命令对其进行监控?
  • 这实际上是我的后备计划。让信号处理程序将信息写入文件而不是 TTY。我想从中获得的信息是正常运行时间、处理的消息数量等,所以如果我可以按需获取这些信息而不是让脚本定期记录它会更好。我想我可能需要编写一个shell脚本来发送USR1信号,然后cat输出文件,然后再删除它。

标签: perl signals tty


【解决方案1】:

最简单的解决方案是 nab 在对您的问题的评论中提出的解决方案:只需将您的输出记录到文件中(可能在您的 $SIG{USR1} 处理程序中),然后对其进行监控。您甚至可以在每次获得 SIGUSR1 时覆盖它。

我正在运行的另一个解决方案是创建一个套接字处理程序。除非您愿意使用一堆模块,否则这会变得更加复杂。我的解决方案是使用AnyEvent + Coro。我将主要工作放在一个 Coro 线程中,启动我的 AnyEvent::Socket::tcp_server(s)(套接字和/或 tcp 端口号),然后在连接时做我需要做的事情(在我的情况下,创建一个一堆线程,在您的情况下,只需像在 $SIG{USR1} 处理程序中一样输出详细信息,然后关闭连接。

真实代码:

AnyEvent::Socket::tcp_server "unix/", "/tmp/cbstats.sock", sub {
    my $fh = shift;
    $fh->binmode(':utf8');
    $fh = unblock $fh;

    $self->handle_connection($fh, @_);

};

然后,因为我是交互式的,所以我运行 socat readline /tmp/cbstats.sock。在您的情况下,您可以在需要输出的任何时候执行socat stdout /tmp/your.socket。 (使用文件系统权限来限制/允许谁可以看到这些数据。)

这里有一点需要注意 - 您需要停止使用 sleep() (或使用 Coro 版本),以便您可以在套接字上接收请求。但是,老实说,它几乎是最小的。然而,我已经将我的服务器切换到使用 AnyEvent 计时器,然后我什至不需要担心睡眠。在那之后,我用它们自己的计时器将多台服务器一起smooshed,一切都运行得很好。

祝你好运。

【讨论】:

  • 我认为输出文件解决方案是我最终会使用的。我将让信号处理程序将输出写入文件,然后我将编写一个 shell 脚本来发送 USR1 信号并将文件的内容转储给用户。谢谢。
【解决方案2】:

你所问的两个主要问题是

  1. 一旦调用 shell 终止,TTY 就会消失/删除
    在我的 Linux 系统上,效果类似于打开/重定向 STDOUT 到文件然后取消链接该文件所发生的情况。除非你在 /proc 中玩糟糕、糟糕的把戏,否则你不会拿回那个输出设备

  2. 信号不携带发件人的 TTY
    既不是minimal specification 也不是implementations which extend the spec

所以,我建议您在终端多路复用器(如 tmuxGNU screen)下运行该实用程序,或者将 STDOUT 重定向到您可以从另一个终端检查的其他输出……比如文件,或者系统日志,或数据库等。

【讨论】:

  • 谢谢。我希望避免使用屏幕等,使其行为更像一个守护进程,并且看起来更“原生”(如果这有意义的话)。不过,我可能需要探索该选项。
  • @Dave,守护进程经常登录到日志子系统,FWIW。
【解决方案3】:

您的操作系统是什么? ps(1) 可以输出任何进程 id 的控制 tty。在 Linux 上,/proc/<pid>/fd/1/proc/<pid>/fd/2 是指向终端或附加进程输出流的文件的符号链接。

【讨论】:

  • 对不起,我应该提到操作系统是 Solaris 10 (SPARC)。我尝试使用 POSIX::sigaction 并在相应的 SigAction 对象上设置 SA_SIGINFO 标志,但即使设置了 SA_SIGINFO 标志,Solaris 也不会将 pid 和 uid(或其他任何内容)传递给处理程序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-17
  • 1970-01-01
  • 2014-12-07
  • 2021-12-01
相关资源
最近更新 更多