2015-10-18 70 views
1

我正在寫一個簡單的實用程序來測試往返幾個主機的往返時間,並選擇平均速度最快的一個。但是,串行而不是並行處理需要一段時間,所以我爲每臺主機產生一個ping進程並從中讀取數據。對於我的使用情況,scalar <$fh>操作會阻塞直到讀取該行足夠好,因爲我無法避免等到最慢的主機超時。但如果我想獲得最快的主機,而不關心其他問題,這是一個不好的方法。有沒有辦法嘗試讀取具有一定時間限制的完整行,並且如果時間限制過去,沒有消耗任何字節就會失敗?Perl嘗試從文件句柄中讀取行而不會阻止

use strict; 
use warnings FATAL => 'all'; 

# generate command to get average 
# round trip length to hostname. 
# we know in advance that each command only 
# emits one line 
sub command { 
    my $host = shift; 
    qq(ping -w 1 -c 5 '$host' |) . 
    q(tail -n 1 |) . 
    q(sed 's/^.*= //;s/ ms//' |) . 
    q(awk -F '/' 'END {print $2}'); 
} 

# launch each ping in its own process and create 
# a filehandle that reads from it 
sub filehandles { 
    my @handles; 
    for my $command (@_) { 
     open my $fh, '-|', $command or 
     die "cannot open file ($!) associated with $command"; 
    push @handles, $fh; 
    } 
    @handles; 
} 

my @commands = map command($_), qw[google.com cnn.com wikipedia.org]; 
my @fhs = filehandles(@commands); 

# read line from each of the ping processes sequentially 
for my $fh (@fhs) { 
    my $line = scalar <$fh>; 
    chomp $line; 
    printf "%s\n", $line || '+INF'; 
} 
+1

你知道Net :: Ping http://perldoc.perl.org/Net/Ping.html,我不知道它是否有僱用超時,但它有超時.. – user993553

+0

我沒有。謝謝。它看起來仍然是,如果我想要並行或同時使用這個模塊做多個ping,我不得不使用多個進程。 –

+0

您可以調用'select'(select-RBITS,WBITS,EBITS,TIMEOUT)或'IO :: Select'(http://perldoc.perl.org/IO/Select.html)。爲了獲得最快的k個響應,請在循環中調用它並記錄每次獲得的響應數量。 –

回答

1

我想我可能會解決你的問題有點像這樣:

#!/usr/bin/perl 

use strict; 
use warnings; 

my $wait_for = 3; #wait for first 3 
my @host_list = qw (server1 server2 server3 server4); 

my %host_for; 

foreach my $host (@host_list) { 
    my $pid = fork; 
    if ($pid) { 
     $host_for{$pid} = $host; 
    } 
    else { 
     my $result = `ping -w 1 -c 5 $host`; 
     last; #so we don't fork bomb 
    } 
} 

for (1..$wait_for) { 
    my $return_pid = waitpid (-1, 0); 
    print "Process $return_pid for $host_for{$return_pid} returned\n"; 
} 

$SIG{'CHLD'} = 'IGNORE'; #we no longer care about return codes of any still running forks. 

有可能有點優化的還有 - 我懷疑你可以使用exec減少過程開銷分叉時,而比使用反引號。 (或者Net :: Ping)

但是這個想法有希望清晰 - 分叉一堆,收穫N個叉,然後將它們的pid與散列做匹配來做IPC,而不必擔心通過返回代碼。儘管您應該檢查fork的返回碼,以確保ping不會完全失敗。

Waitpid會給你$?這將允許你測試成功。