【Perl】複数対象に並列処理でPing死活監視

ネットワーク監視のために、ping死活監視プログラムの作成を依頼されたので記録します。
かなり簡素なものです。

あと、このとき初めてPerlでロクなプログラム書きました。
#スレッド生成#
100対象以上に4秒程の間隔でpingを実行する必要があったため、スレッド処理を行っています。
今思えば、初言語で並列処理とかよくやったなって感じですね...

```pl:autoPing.pl
use threads;

foreach my $i(0 .. $#targetList){
    my $thread = threads->new(
        ¥&runPing,
        $targetList[$i]->[0],
        $targetList[$i]->[1],
        $targetList[$i]->[2],
        $targetList[$i]->[3]
    );
    push(@threads, $thread);
}

foreach(@threads){
    $_->join;
}
```
Perlの並列処理って凄くわかりやすいです。


#まとめ#
こんな感じになりました。

```pl:autoPing.pl
use strict;
use warnings;
use threads;
use Time::HiRes;

my $file = shift;
unless ($file) {
        die "Usage: ¥$ perl $0 <file>.¥n";
}

my @threads;

my $target = ['ip','name','interval','size'];
my @targetList = &getTargetList($file,$target);

print "Create threads.¥n";

foreach my $i(0 .. $#targetList){
    my $thread = threads->new(
        ¥&runPing,
        $targetList[$i]->[0],
        $targetList[$i]->[1],
        $targetList[$i]->[2],
        $targetList[$i]->[3]
    );
    push(@threads, $thread);
}

print "Join threads.¥n";

foreach(@threads){
    $_->join;
}

sub runPing {
    my ($ip,$name,$interval,$size) = @_;
    my $time = sprintf "%0.3f",0;

    while(1){
        my $startTime = Time::HiRes::time;
        my $result = `ping $ip -c 1 -s $size`;
        my $timeStamp = &getTimestamp;

        if($result =~ /¥s1¥sreceived/s){
            $result = "OK : $timeStamp : $name ($ip) -> Packet trancemitted and received. (interval: ${time}s)¥n";
        } elsif ($result =~ /Destination/s) {
            $result = "NG : $timeStamp : $name ($ip) -> Destination Net unreachable. (interval: ${time}s)¥n";
        } elsif ($result =~ /¥s0¥sreceived/s) {
            $result = "OK?: $timeStamp : $name ($ip) -> Packet trancemitted but no received. (interval: ${time}s)¥n";
        } else {
            $result = "NG : $timeStamp : $name ($ip) -> $result (interval: ${time}s)¥n";
        }

        no strict "refs";
        my $fh = "LOG$ip";
        open(${$fh},">> ./log/$ip¥_$name.log") or die("Error : $!");
        print {${$fh}} $result;
        close(${$fh});

        while($interval > Time::HiRes::time - $startTime){
            threads->yield();
        }
        $time = sprintf "%0.3f",Time::HiRes::time - $startTime;
    }
}

sub getTargetList {
#   my (@target) = @_;
    my $targetList = [];

    open(TARGET,"<",$_[0]) or die("Error : $!");
    while(<TARGET>){
        chomp;
        my @target = split(',',);
        push @$targetList, ¥@target;
    }
    close(TARGET);

    for my $target (@$targetList) {
        print join(',',@$target)."¥n";
    }

    wantarray ? return @$targetList : $targetList;
}

sub getTimestamp {
    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
    return sprintf("%04d%02d%02d_%02d%02d%02d",$year+1900,$mon+1,$mday,$hour,$min,$sec);
}
```

実行する際に対象名やIPアドレスをCSVにしたファイルを読み込ませます。
出力結果は対象毎にファイルに分けられて保存されます。
↓出力結果はこんな感じです。

    OK : 20140606_184733 : 対象名 (192.168.*.*) -> Packet trancemitted and received. (interval: 0.000s)
    OK : 20140606_184738 : 対象名 (192.168.*.*) -> Packet trancemitted and received. (interval: 4.000s)
    OK : 20140606_184742 : 対象名 (192.168.*.*) -> Packet trancemitted and received. (interval: 4.000s)
    OK : 20140606_184746 : 対象名 (192.168.*.*) -> Packet trancemitted and received. (interval: 4.011s)
    OK : 20140606_184750 : 対象名 (192.168.*.*) -> Packet trancemitted and received. (interval: 4.014s)

すこし遅延してますね。むむむ
まぁこの時100対象位にping撃ってたんで無理ないか...
hinemosとか、ああいうネットワーク監視ソフトってどんな仕組みなんでしょうね。
気になります。