Link to home
Start Free TrialLog in
Avatar of blizz_ard
blizz_ard

asked on

Net::Ping unexpected result

use Net::Ping;

$p = Net::Ping->new("tcp");
$r = $p->ping($host,2);

The result of this is always null, stating that $host is not up. I checked the host and it is up by doing a ping manually. Why is $r always null? Is there something i did wrong

using icmp works well with the expected result. But it requires to run as root. I do not want to run the script as root.

Thanks.
Avatar of blizz_ard
blizz_ard

ASKER

Here is the output:

discord{ysialend}:80 ~> more test1.pl
#!/usr/local/bin/perl
use Net::Ping;

$host = "172.17.45.8";

$p = Net::Ping->new("tcp");
$r = $p->ping($host,2);

print "I'm up\n" if $r;
print "I'm down\n" if !$r;
discord{ysialend}:81 ~> ping 172.17.45.8
172.17.45.8 is alive
discord{ysialend}:82 ~> test1.pl
I'm down
discord{ysialend}:83 ~>
Using Net::Ping "tcp" protocol requires that the target host respond on the "echo" port, port 7. Most hosts no longer keep this service open. You may have better results from using "external", which will just use the same ping command you used from the command line.
Here is the output:

discord{ysialend}:80 ~> more test1.pl
#!/usr/local/bin/perl
use Net::Ping;

$host = "172.17.45.8";

$p = Net::Ping->new("tcp");
$r = $p->ping($host,2);

print "I'm up\n" if $r;
print "I'm down\n" if !$r;
discord{ysialend}:81 ~> ping 172.17.45.8
172.17.45.8 is alive
discord{ysialend}:82 ~> test1.pl
I'm down
discord{ysialend}:83 ~>
Here is the output:

discord{ysialend}:80 ~> more test1.pl
#!/usr/local/bin/perl
use Net::Ping;

$host = "172.17.45.8";

$p = Net::Ping->new("tcp");
$r = $p->ping($host,2);

print "I'm up\n" if $r;
print "I'm down\n" if !$r;
discord{ysialend}:81 ~> ping 172.17.45.8
172.17.45.8 is alive
discord{ysialend}:82 ~> test1.pl
I'm down
discord{ysialend}:83 ~>
Ok..

I'm doing this now:

$r = `ping $host`;
print "I'm up" if $r =~ /^alive$
print "I'm down" if $r =~ /^no answer$

But the exteranl ping command does not give me the option to specify timeout. So, if a host is unreachable, it will wait around for a good 20 seconds before returning a value.

How do I specifiy a timeout value for this, so that it will try to ping for 2 seconds, and return a value if it has tried for more than 2 seconds?

Thanks
Avatar of FishMonger
Well, since you posted this question twice, I thought I'd post my answer in each.

When I tested this, if unreachable, it responded back in 2 seconds.  Note that you should use icmp instead of tcp since (as jmcg mentions) most hosts will not respond to the tcp ping.  Or you may consider using both in a nested if statement.

#!/usr/bin/perl

use Net::Ping;

$host = "some-host";
$p = Net::Ping->new("icmp");
if ($p->ping($host)) {
  print "I'm up";
} else {
  print "I'm down"
}
$p->close();
Here's an example of using both tcp & icmp.  Depending on the host I tested this on, I was getting (failure) responses rannging from 5 to 10 seconds.  The other example I gave which only used icmp failures ranged from 1.5 to 3 seconds.

#!/usr/bin/perl

use Net::Ping;

$host = "www.microsoft.com";

$p = Net::Ping->new("icmp");
if ($p->ping($host)) {
   print "I'm Up\n";
} else {
   $p = Net::Ping->new("tcp");
   if ($p->ping($host)) {
      print "I'm Up\n";
   } else {
      print "I'm Down\n";
   }
}
$p->close();
ASKER CERTIFIED SOLUTION
Avatar of FishMonger
FishMonger
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
If you don't want to use the Net::Ping module, this is what you're looking for:

#!/usr/bin/perl

$host = "www.microsoft.com";

$r = `ping $host 2`;
print "I'm up\n" if $r =~ /alive/;
print "I'm down\n" if $r =~ /no answer/;
There's been a "blizzard" of multiple postings, but it looks like you have enough stuff to work with.

One thing that may not be clear to FishMonger is that icmp messaging is a privileged operation on Linux/Unix (I don't know about Windows NT/2K/XP); the "icmp" option in Net::Ping may not work if you will not be running the script as root.

If the system at the other end is a web server, it may be best to try to open a connection on port 80, then close it without sending anything. This should not cost anything more than the Net::Ping "tcp" option and will test the operation you really care about rather than testing low-level network connectivity. It will also work in places where pinging does not if, for instance, there's a firewall in place that forbids icmp but allows http on port 80. You can set timeouts on this operation as well.
jmcg, you're right.  I jump between Windows, Solaris, and sometimes Red Hat, unfortunitly, I sometimes forget that the same command doesn't always work the same.  Windows is a lot more relaxed on which users can use "privileged operations".

Your suggestion of testing connectivity to port 80 is probably the best.
There's an example for doing the http check with a two-second timeout in the Net::Ping POD documentation:

    $p = Net::Ping->new("tcp", 2);
    # Try connecting to the www port instead of the echo port
    $p->{port_num} = getservbyname("http", "tcp");
    while ($stop_time > time())
    {
        print "$host not reachable ", scalar(localtime()), "\n"
            unless $p->ping($host);
        sleep(300);
    }
    undef($p);

where the test is repeated every 5 minutes. There's also a discussion of using SYN packets to asynchronously check multiple hosts without needing to be privileged and using Time::HiRes to get more precise measurement of ping times.
There's a lot of answers that I can accept, I'll accept FishMonger answer as fist come first. Thanks to all. Appreciate all the answers