获取在Perl中发送信号的TTY

时间:2012-06-28 15:55:42

标签: perl signals tty

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

./myscript.pl &
kill -USR1 (PID)

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

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

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

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

3 个答案:

答案 0 :(得分:2)

你要问的两个主要问题是

  1. 一旦调用shell终止,TTY就会被删除/删除 在我的Linux系统上,效果类似于将STDOUT打开/重定向到文件然后取消链接该文件时发生的情况。你没有得到那个输出设备,除非你在/proc中发挥可怕的,糟糕的技巧
  2. 信号不带发件人的TTY
    既不是minimal specification也不是implementations which extend the spec
  3. 所以,我建议您在tmuxGNU screen之类的终端多路复用器下运行该实用程序,或者将STDOUT重定向到可以从另一个终端检查的其他输出...就像一个文件,系统日志,数据库等

答案 1 :(得分: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定时器,然后我甚至不用担心睡觉。在那之后,我在他们自己的计时器上将多个服务器混合在一起,并且它们都运行良好。

祝你好运。

答案 2 :(得分:1)

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

相关问题