Interesting problem. I had a similar one myself, except I don't really care which ones are up, just which ones are down, and I needed the results as a percentage so I could graph them.

I also discovered that trying to ping a huge number of hosts one at a time was painfully slow, so I wrote the following.

Bear in mind that this program is designed to pull the list of targets from a MySQL database, you could easily modify it to read in a config file though. It also doesn't handle forking the most efficient way possible, in that it doesn't ALWAYS keep $maxforks children running, it just runs them in bursts of $maxforks, but I find it's plenty fast enough even when pinging several hundred targets. I also used the system call to ping instead since I couldn't install CPAN modules on the machine it was running on. Again, that's probably a three-minute change.

Hope you find it interesting...
#!/usr/bin/perl -- # # ForkingPinger # Pings a list of remote hosts and calculates an uptime # percentage based on the number of responses. If run in # interactive mode, lists the sites that failed. # # (C) 2001 James Mancini <wfe@networkavatar.com> # Please send copies of modifications or improvements to # the author! # # Released under the same terms as perl itself. # # THIS PROGRAM IS PROVIDED WITH NO WARRANTY - USE AT YOUR # OWN RISK. # # 21 Mar 2001 my $Version = "0.2.2 - beta"; use DBI; use Getopt::Long; use POSIX ":sys_wait_h"; $|++; #autoflush output for speed ######################### # MAIN ######################### my (%opt, @targets); my $maxprocs = $opt{max} || 50; # set the maximum number of childre +n to spawn $main::avail = 0; &options(\%opt); &get_targets(); &check_remotes(); ######################### sub get_targets ######################### { ## Set up vars for main db call my ($dsn) = "DBI:mysql:routers:localhost"; my ($user_name) = "user"; my ($password) = "abcd1234"; my ($dbh, $sth); ## Connect to DB $dbh = DBI->connect ( $dsn, $user_name, $password, {RaiseError =>1} ); ## Fetch variables from database and write out config file ## The Database Query is option dependant if ($opt{cat}) { $sth = $dbh->prepare ("SELECT ip FROM routers WHERE category rlike + '$opt{cat}'"); } elsif ($opt{all}) { $sth = $dbh->prepare ("SELECT ip FROM routers"); } else { die "ERROR - Couldn't identify a target. $!"; } ## Go get it $sth->execute(); ## Process the data while( ($ip_add) = $sth->fetchrow_array() ) { push @targets, $ip_add; $noerror = "1"; } ## Disconnect the DB $sth->finish (); $dbh->disconnect(); unless ($noerror) {die "FATAL: Database did not return valid data! Che +ck Device name.\nError Response: $!\n";} } ######################### sub check_remotes ######################### { my $prox = int(scalar(@targets)/$maxprocs); my $prox_r = int(scalar(@targets)%$maxprocs); my $i = 0; if ($prox) { for ( 1 .. $prox ) # call the forking routine as many times as requ +ired to get most of the targets { &breed($maxprocs); } } if ($prox_r) { &breed($prox_r); # Then call the forking routine but this time on +ly enough to catch the modulo } # Calculate results and print to STDOUT my $uptime = ( $main::avail / scalar(@targets) ) * 100; # return res +ults as a percentage $uptime = sprintf('%.2f',$uptime); print "\nTOTAL:\t${uptime}% of devices are responding.\n"; } ######################### sub breed ($) ######################### { my $loop = shift; for ( 1 .. $loop ) { if ($pid=fork) { push @pids, $pid; $i ++; } elsif (defined $pid) { my $next = @targets[${i}]; &ping_remote($next); exit; } } foreach my $childpid (@pids) { waitpid($childpid, 0); $main::avail += ! $?; # 0 means success, non-zero means failure } } ######################### sub ping_remote($) ######################### { my $ip = shift; my $response = `ping -n -w 5 -i .3 $ip -c 3 | grep round-trip`; chomp $response; if ($response) { $response = 0; } else { $response = 1; } # 0 means su +ccess, non-zero means failure if (-t and $response) { print "Failed connect to $ip\n"; } exit($response); } ######################## sub options () ######################## { my $opt = shift; GetOptions( $opt, 'cat=s', 'max=s', 'all', ); $opt{cat} =~ s/[\"\;]//; # remove quotes and semicolons from querie +s unless (defined $opt{cat} || $opt{all}) #print usage if options not + given { print <<ECHO; ForkingPinger, Version $Version --------- Pulls a category from the database and checks it for availability, ret +urning a percentage. Designed to be run in batch mode but can be used at the command line f +or debugging or testing purposes. Highly parallel. Automatically prints the IP addresses of failed sites if used from the + command line. Usage: $0 [options] Options: --cat=name Pull all devices of category matching regexp 'name' from DB and test a +vailability. --all Pull all devices from DB and test availability. --max=num Spawn no more than num processes in parallel (default = 50) ECHO exit(1); } }
Update: Fixed a little typo I spotted. Oops.
Update2: Fixed a bigger omission: the -all switch was broken. I wasn't considering the option when validating command line switches. Oops again.
Signature void where prohibited by law.

In reply to Forking Pinger by Clownburner
in thread Pingger by muaddib2

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.