Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

is there script to detect if remote machine is alive/reachable w/o using Net::Ping?

by Anonymous Monk
on Jun 06, 2002 at 18:45 UTC ( [id://172314]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Is there a script which is cross-platform and can detect if a remote machine is ALIVE/Reachable without using the NET::PING? Im currenlty using a Redhat Linux and the PING command there seems to also "HANG" on unreachable machines, thats why i just cant use backticks for this. The reason why i want to detect if a certain machine is alive/reachable is because when my TCP IO::SOcket CLIENT connects to a certain "UNREACHABLE MACHINE" it also hangs. i dont want to place a DIE after because i still have other commands that need to be executed after. Heres a sample code:
sub doit { $host="$aa.$bb.$cc.$dd"; $port="23"; $remote = IO::Socket::INET -> new ( Proto => "tcp", PeerAddr => $host, PeerPort => $port, Timeout => 1 ); $| = 1; if ($remote) { close $remote; print "Socket ready..."; } else { print "Try again!"; } }
Although the TIMEOUT has been set to 1. It still takes too much time to wait for it to die and go to the next command. probably around 5 minutes. So is there any workaround for this? Shutdown ($remote, 1) doesnt seem to work, perl says that $remote is an uninitialized variable. $remote->close; doesnt seem to work either? Please help... connecting a socket on an UNREACHABLE MACHINE takes too much time and TIMEOUT doesnt help out that much either. it seems as if my script HANGed! tnx... Lovelots, Cherry

Replies are listed 'Best First'.
Re: is there script to detect if remote machine is alive/reachable w/o using Net::Ping?
by u914 (Pilgrim) on Jun 06, 2002 at 18:59 UTC
    if the machine is supposed to be running an http server, you could use LWP to see if the httpd responds.

    use LWP::UserAgent; $ua = new LWP::UserAgent; $ua->agent("AgentName/0.1 " . $ua->agent); my $req = new HTTP::Request GET => "http://some.server.net/"; my $res = $ua->request($req); if ($res->is_success) { #server is alive, do something } else { #something wrong, do something }
    warning: that code was cribbed from the LWP pages, and might not be correct for your application....

    update:

    you could use the die as you suggested too, if you trap it with an eval() statement...

    see this node for an excellent example.

    good luck!

Re: is there script to detect if remote machine is alive/reachable w/o using Net::Ping?
by mojotoad (Monsignor) on Jun 06, 2002 at 20:29 UTC
    If you are merely polling, rather than attempting to yank an entire web page, I'd recommend using the 'HEAD' method in your request object rather than 'GET'. So modify 914's suggestion thusly to save some time and bandwidth:

    my $req = new HTTP::Request HEAD => "http://some.server.net/"; my $res = $ua->request($req);

    This is still assuming that HTTP is indeed the service of interest.

    Matt

      Like merlyn says, just be sure that if the HEAD fails try again with a GET. Many servers are configured not to respond to HEAD requests.
Re: is there script to detect if remote machine is alive/reachable w/o using Net::Ping?
by ehdonhon (Curate) on Jun 06, 2002 at 23:35 UTC
    Im currenlty using a Redhat Linux and the PING command there seems to also "HANG" on unreachable machines

    Did you specify a timeout period for ping? You can use -t to tell ping when you want it to exit. Here's some code that returns true if the remote machine pings at least once in 7 seconds:

    sub ping { my $ip = shift; my $p = `/sbin/ping -c 5 -t 7 $ip | /usr/bin/grep 'packet loss'`; unless ( $p =~ /(\d+)% packet loss/ ) { die ( "Bad Response:\n$p\n" ); } my $loss = $1; print "Loss = $1 "; return ( $loss != 100 ); }

      Are you on RedHat? iputils-ss001110 uses -t for time-to-live. I've got -w for timeout. Oh well, no matter.


        tnx very much guys! i really appreciated the help. even though my question was not specific. im really sorry about it. my question shouldve been like this:
        In general IO::Socket process (regardless of which socket and what typ +e of socket to use) what should be the recommended process to detect +if the remote machines are alive/reachable if you dont want to put a +DIE command after the IO::Socket::INET->new() process? (of course, to + avoid HANG and probably you would have other codes to execute after +the socket connect process...)
        The only thing I thought about at that time was PING. And yes I did forget to check the man pages, sorry for that. heres what i did.:
        sub doit { $host="$aa.$bb.$cc.$dd"; $port="23"; $fnd=""; $pong=`ping -c 3 $host -v`; #is there really a "-t" option here? $fnd=($pong=~m/(...)%/gi); $xcd=$1; if ($xcd!=100) { $remote = IO::Socket::INET -> new ( Proto => "tcp", PeerAddr => $host, PeerPort => $port, Timeout => 1 ); $| = 1; if ($remote) { close $remote; print "Socket ready..."; } else { print "Try again!"; } } }
        tnx really a lot for helping me. but i do have one inquiry though. "Is there a way to detect remote machines if they are alive/reachable w/o using NET::Ping and the shell command /sbin/ping?" Hopefully something like a socket command. thank you very much to all those who helped me. Lovelots and *mwah*, Cherry.
Re: is there script to detect if remote machine is alive/reachable w/o using Net::Ping?
by grinder (Bishop) on Jun 07, 2002 at 10:32 UTC

    odd you should say that. I use almost exactly the same code and I have never been troubled with lengthy delays. Are you sure you don't have a problem with DNS name resolution (even though your example shows the use of numeric IP addresses)?

    Here is the code I use. It is part of a CGI script, so there is a $q CGI object hanging around, and a few constant values for pretty colors, such as use constant PAINT_OK => '#008000' and so on.

    sub test_socket { my $s = IO::Socket::INET->new( @_, Timeout=>2, Proto => 'tcp' ); if( $s ) { close $s; $q->font( {-color=>PAINT_OK}, 'ok' ); } else { $q->font( {-color=>PAINT_NOK}, $! ) } } my %tcp_probe = ( 'foo<br>Apache' => test_socket( PeerHost => '172.17.0.2', Pe +erPort => 80, ), 'foo<br>Lotus' => test_socket( PeerHost => '172.17.0.2', Pe +erPort => 1352, ), 'bar<br>Apache' => test_socket( PeerHost => '172.17.0.3', Pe +erPort => 80, ), 'bar<br>Lotus' => test_socket( PeerHost => '172.17.0.3', Pe +erPort => 1352, ), 'example<br>Apache' => test_socket( PeerHost => 'www.example.com', + PeerPort => 80, ), 'example<br>Domino' => test_socket( PeerHost => 'www.example.com', + PeerPort => 8000, ), 'example<br>Lotus' => test_socket( PeerHost => 'www.example.com', + PeerPort => 1352, ), 'Web<br>Proxy' => test_socket( PeerHost => '172.17.0.9', + PeerPort => 8080, ), 'baz<br>Sybase' => test_socket( PeerHost => '172.17.0.1', Peer +Port => 4100, ), 'baz<br>Samba' => test_socket( PeerHost => '172.17.0.1', Peer +Port => 139, ), ); print $q->h3('Mission Critical'), $q->table( $q->TR( $q->th( {-width=>60, -valign=>'bottom', -bgcolor=>'#fff0e0'}, [ sort keys %tcp_probe ] ) ) . $q->TR( $q->td( {-width=>60, -align=>'center'}, [ map { $tcp_probe{$_} } sort keys %tcp_probe ] ) ) );

    The only other thing I could suggest would be to set an alarm of a second or two, an alarm handler and eval the code, in order to forcibly cancel the code. But if it's blocking at a low enough level, alarm won't necessarily work either, I've had that happen in the past.


    print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u'
      tnx guys, ive tried what GRINDER recommended and heres what happened to my code:
      use IO::Socket; sub doit { $ip1="210.22.106.31"; $host="$ip1"; $port="23"; $fnd=""; $pong=`ping -c 3 $host`; $fnd=($pong=~m/(..)%/gi); $xcd=$1; if ($xcd!=00) { $SIG{ALRM} = \&timed_out; eval { alarm (3); $remote = IO::Socket::INET -> new ( Proto => "tcp", PeerAddr => $host, PeerPort => $port, Timeout => 2 ) or die "." ; alarm (0); }; sub timed_out { die "."; } $| = 1; if ($remote) { close $remote; print "Socket ready...\n"; } else { print "Try again...\n"; } } else { print "Pinged timed out!\n"; }
      This doenst seem to work? It also hangs just as before? sigh... got any substitute for EVAL which works for Sockets? Thank you all for helping me. I really dont know what to do next? Lovelots and *mwah* *mwah* *mwah*, Cherry.
Re: is there script to detect if remote machine is alive/reachable w/o using Net::Ping?
by hacker (Priest) on Jun 07, 2002 at 12:51 UTC
    Let's also not forget that ping is completely unreliable way of validating machine health. Just because an interface responds to requests (icmp echo for example) does not mean that services on that box are properly listening. I hear this all the time:
    "I pinged your machine so I know it's working, but I can't see your website. What else could be wrong?"

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://172314]
Approved by Aristotle
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (5)
As of 2024-04-25 11:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found