2010-01-27 56 views
3

是否有可能,我將能夠產生一個分離的守護進程的過程中,從一個CGI腳本 ,存儲在內存中讀取文本文件,然後重新訪問內存中的下一個CGI的執行,使用管道讀取數據?如何從CGI中分離進程,以便能夠從內存中存儲和讀取文件?

最會主辦的ISP,讓超脫流程?內存管道是否快速,並且易於在unix/linux系統上進行編碼/工作?

是否有解決方案,可以在不使用任何額外的CPAN模塊來完成?這是一個CGI過程,所以我想把它保持在最低限度。

+0

+1有趣的問題 – Nifle 2010-01-27 16:27:53

回答

0

假設你有一個簡單的resource.cgi

#! /usr/bin/perl 

use warnings; 
use strict; 

use Reader; 
use CGI qw/ :standard /; 

print header("text/plain"), 
     "Contents:\n", 
     Reader::data, 
     "-" x 40, "\n"; 

它的輸出是

Content-Type: text/plain; charset=ISO-8859-1 

Contents: 
This is a data file 
with some very interesting 
bits. 
----------------------------------------

有趣的部分是在Reader.pm,與熟悉的前瞻性樣板開始:

package Reader; 

use warnings; 
use strict; 

use Fcntl qw/ :DEFAULT :flock :seek /; 
use POSIX qw/ setsid /;  

接下來它定義了集合點:

my $PIDFILE = "/tmp/reader.pid"; 
my $DATA = "/tmp/file.dat"; 
my $PIPE = "/tmp/reader.pipe"; 

該子import is called as part of use Module。如果守護進程已經在運行,那麼就沒有什麼可做的了。否則,我們分離守護進程並將其進程ID寫入$PIDFILE

sub import { 
    return unless my $fh = take_lock(); 

    my $child = fork; 
    die "$0: fork: $!" unless defined $child; 

    if ($child) { 
    print $fh "$child\n" or die "$0: write $PIDFILE: $!"; 
    close $fh    or die "$0: close $PIDFILE: $!"; 
    return; 
    } 

    # daemonize 
    close $fh; 
    chdir "/"; 
    open STDIN, "<", "/dev/null"; 
    open STDOUT, ">", "/dev/null"; 
    open STDERR, ">", "/dev/null"; 
    setsid; 

    open $fh, "<", $DATA or die; 
    undef $/; 
    my $data = <$fh>; 
    close $fh; 

    while (1) { 
    open my $fh, ">", $PIPE or die; 
    print $fh $data   or die; 
    close $fh; 
    } 
} 

每個客戶端都需要等到輪到它鎖定$PIDFILE。一旦我們有了鎖定,我們就會檢查確定的進程是否仍在運行,並在必要時創建命名管道。

sub take_lock { 
    sysopen my $fh, $PIDFILE, O_RDWR | O_CREAT or die "$0: open $PIDFILE: $!"; 
    flock $fh => LOCK_EX      or die "$0: flock $PIDFILE: $!"; 

    my $pid = <$fh>; 

    if (defined $pid) { 
    chomp $pid; 

    if (kill 0 => $pid) { 
     close $fh; 
     return; 
    } 
    } 
    else { 
    die "$0: readline $PIDFILE: $!" if $!; 
    } 

    sysseek $fh, 0, SEEK_SET or die "$0: sysseek $PIDFILE: $!"; 
    truncate $fh, 0   or die "$0: truncate $PIDFILE: $!"; 

    unless (-p $PIPE) { 
    system("mknod", $PIPE, "p") == 0 
          or die "$0: mknod exited " . ($? >> 8); 
    } 

    $fh; 
} 

最後,閱讀管道很簡單:

sub data { 
    open my $fh, "<", $DATA or die "$0: open $DATA: $!"; 
    local $/; 
    scalar <$fh>; 
} 

不要忘了從模塊返回真值:

1; 

你會注意到,操作仍然在守護進程中失敗。爲了您的理智,您需要以某種方式記錄事件,而不是默默地窒息。

至於主機是否將允許長時間運行的進程,這將改變從供應商提供的,但即使你的守護進程是從時間殺死時間,上面的代碼將重新啓動它的需求。

1

如果你絕對需要的文件的內容存在於內存中,更簡單的解決辦法是建立一個RAM磁盤,並將它們存儲在那裏。那麼你不必對cgi-scripts做任何特殊的事情。

+0

我要尋找一個便攜式解決方案...這在平均共享網絡託管服務器上有兩項工作: – 2010-01-27 15:56:03

+0

@Jera - 我懷疑內存磁盤解決方案的可移植性不及「產生deamons和與管道通信」。 – Nifle 2010-01-27 16:26:40

+0

怎麼這樣?我不是RAM磁盤專家,我如何輕鬆地在主機上設置它?所有主機都會允許嗎? – 2010-01-27 17:01:03

相關問題