'How to check the presence of the internet connection in Perl?

I have a simple script that verifies periodically (once every few seconds) if there is internet connectivity from that server. To be clear, it's not about to check if an external site/service/server is alive. As reliable internet destinations I use IPs of sites like google, yahoo, etc. Normally I use 3 destinations (LAN, ISP network, outside ISP)

My current code responsible for this is just a simple and dirty call to ping:

    my $pingResponse = `ping -c 1 -w 1 123.123.123.123`;
    my $isConnected = parsePingResponse($pingResponse);

It seems to work, but I'm sure it's not the right/best way to accomplish this task. There are at least 3 drawbacks: external system call, it's slow, it has a relatively long deadline of 1 second.

So, my question is: how to implement simply and efficiently a ping functionality the perlish way in order to verify if the internet connection is alive?

(I think LWP is an overkill. It's not important if a site or a page is available, just if some external IPs are reachable. Probably it should be something simple involving low-level networking)



Solution 1:[1]

The perlish way to do this would be Net::Ping.

my $p = Net::Ping->new;
if ($p->ping("123.123.123.123", 1)) {
    print "Host is reachable\n";
}

The timeout may be a float (e.g. 0.5) if you want the command to run faster. You'll need to choose a timeout that fits your needs; a higher timeout is more likely to be correct about the internet connectivity, but will take longer.

Solution 2:[2]

The example given by rjh above does not work in many cases because he did not initialize the constructor properly. This example below might help:

use Net::Ping;

my $p = Net::Ping->new("icmp");
while(1){
printf "Checking for internet\n";
    if ($p->ping("www.google.com")){
    printf "Internet connection is active!\n";
        sleep 1;
    last; #break out of while loop if connection found
    }
    else{
    printf "Internet connection not active! Sleeping..\n";
        sleep 60*60;
    }   
}

Solution 3:[3]

The answer with a ping to google above (from 2013) has the advantage that it does not rely on a number to check internet connection as so it is arguably slightly more general. However in typical environments in 2019 it will only work if some parts of it are modified to catch an error of name resolution when connection is not up. This is a way to do that in perl. In a Debian context it can be started eg with 'sudo perl program.pl' from Terminal:

use warnings;
use strict;
use Net::Ping;
my $p = Net::Ping->new("icmp");
my $netstatus = 1;
eval { $p->ping("www.wikipedia.org"); 1; }
or do { $netstatus = 0; };
if ($netstatus == 1 )
  { printf "Internet connection is active!\n"; }
else
  { printf "Internet connection not active.\n"; }

Solution 4:[4]

The answer I gave a moment ago, with a ping of wikipedia, requires root privileges (eg, "sudo") to be started. In order to avoid giving root privileges to the program, one can either ping through command line and read its output, or install the experimentative perl extension libnet_ping_external, eg at https://launchpad.net/ubuntu/zesty/amd64/libnet-ping-external-perl/0.13-1 (The .deb at that page is saved and after you verify its authenticity, you can open it for install eg through File Manager.) Credit to https://forums.gentoo.org/viewtopic-p-2920594.html for this approach. Here is an example that works (although slower), using this module, to ping inside perl without root privileges.

use warnings;
use strict;
use Net::Ping::External qw(ping);
my $connected = ping(host => "www.google.com");
if ($connected)
  { printf "Internet connection is active!\n"; }
else
  { printf "Internet connection not active.\n"; }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 rjh
Solution 2 djaa2807
Solution 3 Aristo
Solution 4 Aristo