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

时间:2015-01-24 14:10:25

标签: linux apache perl cgi

我在Linux(Ubuntu 14.04)上运行一个简单的apache Web服务器,并使用perl CGI脚本处理一些请求。该脚本使用system函数启动系统命令,但我希望它立即返回,而不管系统调用的结果如何。

我已经在传递给system的标量参数的末尾添加了&符号(我知道命令注入攻击的含义)虽然这确实会导致系统命令立即返回,脚本仍然不会退出,直到底层命令完成。

如果我使用来自perl CGI的system调用触发10秒睡眠的虚拟ruby脚本,那么我对Web服务器的请求仍然等待10秒才能最终获得响应。我在system调用之后放了一个日志语句,它在Web请求发生时立即显示,因此system调用肯定会立即返回,但脚本仍在等待结束。

This question类似,但这些解决方案都没有对我有用。

以下是一些示例代码:

#!/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调用的命令完成。为什么呢?

1 个答案:

答案 0 :(得分:4)

Web服务器创建一个管道,从中接收响应。在完成请求之前,它等待管道到达EOF。当关闭编写器句柄的所有副本时,管道达到EOF。

管道的作者端被设置为孩子的STDOUT。该文件句柄被复制为shell的STDOUT,并再次复制到mycmd的STDOUT。因此,即使CGI脚本和shell结束并因此关闭了文件句柄的末尾,mycmd仍然保持句柄打开,因此Web服务器仍在等待响应完成。

您只需关闭管道编写器末端的最后一个句柄即可。或者更准确地说,您可以通过将不同的句柄附加到mycmd STDOUT来避免首先使用它。

mycmd arg1 arg2 </dev/null >/dev/null 2>&1 &
相关问题