3

我有一个 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 名称的好方法。

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

4

3 回答 3

2

你所问的两个主要问题是

  1. 一旦调用 shell 终止,TTY 就会消失/删除
    在我的 Linux 系统上,效果类似于打开/重定向 STDOUT 到文件然后取消链接该文件时发生的情况。除非你在/proc

  2. 信号不携带发送者的 TTY
    既不是通过最小规范也不是通过扩展规范的实现

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

于 2012-06-28T16:28:03.037 回答
2

最简单的解决方案是 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,一切都运行得很好。

祝你好运。

于 2012-06-28T19:11:28.327 回答
1

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

于 2012-06-28T16:15:17.910 回答