2010-01-19 72 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患淨一堆投訴同樣的問題,所以如果有人遇到同樣的問題,我懷疑同樣的解決方案會起作用。