2015-10-18 69 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会给你$?这将允许你测试成功。