You want to test whether a machine is alive. Network- and system-monitoring software often use the ping program as an indication of availability.
Use the standard Net::Ping module:
use Net::Ping; $p = Net::Ping->new( ) or die "Can't create new ping object: $!\n"; print "$host is alive" if $p->ping($host); $p->close;
Testing whether a machine is up isn't as easy as it sounds. It's not only possible but also unpleasantly common for machines to respond to the ping command when they have no working services. It's better to think of ping as testing whether a machine is reachable, rather than whether the machine is doing its job. To check the latter, you must try its services (Telnet, FTP, web, NFS, etc.).
In the form shown in the Solution, Net::Ping attempts to connect to the TCP echo port (port number 7) on the remote machine. The ping method returns true if the connection could be made, false otherwise.
You can also ping using other protocols by passing the protocol name to new. Valid protocols are tcp, udp, syn, and icmp (all lowercase). A UDP ping attempts to connect to the echo port (port 7) on the remote machine, sends a datagram, and attempts to read the response. The machine is considered unreachable if it can't connect, if the reply datagram isn't received, or if the reply differs from the original datagram. An ICMP ping uses the ICMP protocol, just like the ping(8) command. On Unix machines, you must be the superuser to use the ICMP protocol:
# use TCP if we're not root, ICMP if we are $pong = Net::Ping->new( $> ? "tcp" : "icmp" ); (defined $pong) or die "Couldn't create Net::Ping object: $!\n"; if ($pong->ping("kingkong.com")) { print "The giant ape lives!\n"; } else { print "All hail mighty Gamera, friend of children!\n"; }
A SYN ping is asynchronous: you first send out many pings and then receive responses by repeatedly invoking the ack method. This method returns a list containing the hostname, round-trip time, and the IP address that responded:
$net = Net::Ping->new('syn'); foreach $host (@hosts) { $net->ping($host); } while (($host, $rtt, $ip) = $net->ack( )) { printf "Response from %s (%s) in %d\n", $host, $ip, $rtt; }
Of course, most machines don't take a second or more to set up a TCP connection. If they did, you'd find web browsing painfully slow! To get anything but 0 second round-trip times back from this test, you need more granularity in your time measurements. The hires method uses Time::HiRes (see Recipe 3.9) to measure ACK times. The following code snippet enables high-resolution timers (changed code appears in bold):
$net = Net::Ping->new('syn'); $net->hires( ); # enable high-resolution timers foreach $host (@hosts) { $net->ping($host); } while (($host, $rtt, $ip) = $net->ack( )) { printf "Response from %s (%s) in %.2f\n", $host, $ip, $rtt; }
The value in $rtt is still in seconds, but it might have a decimal portion. The value is accurate to milliseconds.
If using TCP to ping, set the port that Net::Ping uses. This might mean a service is present although any industrial-grade monitoring system will also test whether the service responds to requests:
$test = Net::Ping->new('tcp'); $test->{port_num} = getservbyname("ftp", "tcp"); if (! $test->ping($host)) { warn "$host isn't serving FTP!\n"; }
All these ping methods are prone to failure. Some sites filter the ICMP protocol at their router, so Net::Ping would say such machines are down even though you could connect using other protocols. Similarly, many machines disable the TCP and UDP echo services, causing TCP and UDP pings to fail. There is no way to know whether the ping failed because the service is disabled or filtered, or because the machine is actually down.
The documentation for the Net::Ping module from CPAN; your system's ping(8), tcp(4), udp (4), and icmp(4) manpages (if you have them); RFCs 792 and 950