结束Perl脚本而不等待系统调用返回

3
我在Linux(Ubuntu 14.04)上运行简单的Apache Web服务器,并使用一个Perl CGI脚本处理一些请求。该脚本使用“system”函数启动系统命令,但我希望它无论系统调用的结果如何都能立即返回。 我已经在传递给“system”函数的标量参数末尾添加了一个&符号(我知道这可能会导致命令注入攻击),虽然这确实使得系统命令能立即返回,但是直到底层命令完成之前,脚本仍将不会退出。如果我从Perl CGI使用“system”调用触发一个具有10秒休眠的虚假Ruby脚本,则我的Web服务器请求仍需等待10秒才能最终得到响应。我在“system”调用后放置了日志语句,并在Web请求时立即出现,所以“system”调用肯定能够立即返回,但脚本仍将停留在结尾处。这个问题类似于这个问题,但两个解决方案对我都没有起作用。以下是一些示例代码:
#!/usr/bin/perl
use strict;
use warnings;
use CGI;
use Log::Log4perl qw(:easy);

Log::Log4perl->easy_init(
    { level => $DEBUG, file => ">>/var/log/script.log" } );

print "Content-type: application/json\n\n";
my $cgi = CGI->new();

INFO("Executing command...");
system('sudo -u on-behalf-of-user /tmp/test.rb one two &');
INFO("Command initiated - will return now...");

print '{"error":false}';
编辑:
使用 sudo -u 执行命令是因为 Apache 用户 www-data 需要获得脚本所有者的执行权限,我已经相应地更新了我的 sudoers 文件。这不是我遇到问题的原因,因为我也尝试将脚本所有权更改为 www-data 并运行 system("/tmp/test.rb one two &"),但结果仍然相同。 编辑2:
我还尝试在脚本的末尾添加 exit 0,但没有任何区别。可能脚本立即退出,但 Apache 服务器一直保持响应,直到 perl CGI 调用的命令完成吗?或者操作系统的某些设置或配置会导致问题? 编辑3:
从终端直接运行 perl CGI 脚本可以正常工作。Perl 脚本立即结束,因此这不是 Perl 的固有问题。这预示着 Apache Web 服务器会保持请求直到从 system 中调用的命令完成。为什么?

我知道它们几乎相同,但在那个问题中,我特别询问了关于system调用的数组版本,以防止命令注入。无论如何,没有一个这些解决方案适用于我,导致与本问题描述相同的行为。此外,当我接受那个问题的答案时,我没有进行适当的测试,所以我没有意识到它仍然无法正常工作。 - RTF
1个回答

4

Web服务器创建一个管道来接收响应。它会等待管道到达EOF(文件结束)才完成请求。当写入句柄的所有副本都关闭时,管道到达EOF。

管道的写入端被设置为子进程的STDOUT。该文件句柄被复制为shell的STDOUT,再次复制为mycmd的STDOUT。因此,即使CGI脚本和shell已经结束并关闭了它们的文件句柄,mycmd仍然保持着句柄打开状态,因此Web服务器仍在等待响应完成。

你只需要关闭管道写入端的最后一个句柄。或者更准确地说,你可以通过将不同的句柄附加到mycmd的STDOUT上来避免首先制造它。

mycmd arg1 arg2 </dev/null >/dev/null 2>&1 &

太棒了,非常感谢,它起作用了。我理解你所说的问题原因,但我不确定我理解解决方案。为什么将 /dev/null 重定向到 stdin、stdout 和 stderr 可以解决这个问题? - RTF
1
我刚刚改进了我的回答中的解释。 - ikegami
1
@vol7ron,提供新的STDIN只是常识。为什么子进程想要从用于与CGI脚本通信的管道中读取数据呢?这样做没有好处。至于STDERR,它就像STDOUT一样,是连接到Web服务器的管道。 - ikegami
1
Daemon::Daemonize 展示了创建一个独立进程时通常要做的事情。在这种情况下,shell 处理双重 fork 和创建新会话,留给你的工作是为 STD* 提供一些东西。 - ikegami
1
标准输入?不,Web服务器不会等待它达到EOF,因为它是写入者。 - ikegami
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接