2010-01-19 74 views
6

我有一个使用IPC :: Open3(或IPC :: Open2,都出现此问题)的模块来调用外部二进制文件(在这种情况下为bogofilter)并通过一些输入子输入文件句柄,然后从子输出句柄中读取结果。该代码在大多数环境中运行时工作正常。但是,这个模块的主要用途是在Apache 2.2.6下运行的Web服务中。而这环境下,我得到的错误:IPC :: Open3在Apache下运行失败

无法fdopen STDOUT:无效的参数

这只有在代码Apache下运行的情况。之前,代码构建了一个非常复杂的命令,其中包含一个用于输入的here-document,并用反拨号运行它。这工作,但非常缓慢,容易打破独特和令人困惑的方式。我讨厌不得不恢复到旧版本,但我无法解决这个问题。

回答

1

难道是因为mod_perl 2关闭了STDOUT?我刚刚发现这一点,并发布了关于它:

http://marc.info/?l=apache-modperl&m=126296015910250&w=2 

我认为这是一个讨厌的错误,但似乎没有人去关心它迄今。如果您的问题是相关的并且您希望得到关注,请在mod_perl列表上发布后续信息。

乔恩

+0

我想你是在正确的轨道上! – Ryley 2014-06-19 15:34:25

0

Bogofilter返回/不是垃圾邮件不同的退出代码。

您可以通过标准输出重定向到/ dev “修理” 这个/空

system("bogofilter < $input > /dev/null") >> 8; 

将垃圾邮件的nonspam,2返回0,1未知(该>> 8是因为Perl有益修正退出代码,这修复了损害)。

注:缺乏的环境中还可以防止bogofilter从寻找它的单词表,所以把它传递明确,以及:

system("bogofilter -d /path/to/.bogofilter/ < $input > /dev/null") >> 8; 

(其中/path/to/.bogofilter包含wordlist.db)

您无法检索bogofilter以此方式给出的实际评分,但它确实为您提供了某种功能。

+0

我不认为这是直接的问题 - 如果有需要专门使用Open3的话。 – Ryley 2014-06-19 15:33:56

0

如果你的代码,只是要在Linux/Unix系统运行很容易写的open3更换不失败,因为stdout是不是一个真正的文件句柄:

sub my_open3 { 
    # untested! 
    pipe my($inr), my($inw) or die; 
    pipe my($outr), my($outw) or die; 
    pipe my($errr), my($errw) or die; 
    my $pid = fork; 
    unless ($pid) { 
     defined $pid or die; 
     POSIX::dup2($inr, 0); 
     POSIX::dup2($outw, 1); 
     POSIX::dup2($errw, 2); 
     exec @_; 
     POSIX::_exit(1); 
    } 
    return ($inw, $outr, $errr); 
} 

my ($in, $out, $err) = my_open3('ls /etc/'); 
0

买者自负:我我不是一个perl向导。

正如@JonathanSwartz所建议的,我认为问题在于apache2 mod_perl关闭了STDIN和STDOUT。这与IPC :: Open3没有什么关系,但它有一个缺陷,described here。总之(这是我没有超清楚的部分),open3会尝试将子进程STDIN/OUT/ERR与您的进程匹配,或者如果请求发生了重复,那么open3会尝试将子进程与STDIN/OUT/ERR进行匹配。由于一些未公开的方式('> & = X')起作用,除了STDIN/OUT/ERR关闭的情况以外,它通常工作正常。

Another link深入细节。

一个解决方案是修复IPC :: Open3,如这两个链接中所述。另外,这工作对我来说,是/ OUT在你的mod_perl代码临时打开STDIN,然后再把其关闭:

my ($save_stdin,$save_stdout); 
open $save_stdin, '>&STDIN'; 
open $save_stdout, '>&STDOUT'; 
open STDIN, '>&=0'; 
open STDOUT, '>&=1'; 

#make your normal IPC::Open3::open3 call here 

close(STDIN); 
close(STDOUT); 
open STDIN, '>&', $save_stdin; 
open STDOUT, '>&', $save_stdout; 

而且,我注意到周围约IPC :: RUN3患净一堆投诉同样的问题,所以如果有人遇到同样的问题,我怀疑同样的解决方案会起作用。