LoginSignup
4
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-06-06

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

あと、このとき初めてPerlでロクなプログラム書きました。

スレッド生成

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

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の並列処理って凄くわかりやすいです。

まとめ

こんな感じになりました。

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とか、ああいうネットワーク監視ソフトってどんな仕組みなんでしょうね。
気になります。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4