How can I see if there's an available and active network connection in Python? How can I see if there's an available and active network connection in Python? python python

How can I see if there's an available and active network connection in Python?


Perhaps you could use something like this:

import urllib2def internet_on():    try:        urllib2.urlopen('http://216.58.192.142', timeout=1)        return True    except urllib2.URLError as err:         return False

Currently, 216.58.192.142 is one of the IP addresses for google.com. Change http://216.58.192.142 to whatever site can be expected to respond quickly.

This fixed IP will not map to google.com forever. So this code isnot robust -- it will need constant maintenance to keep it working.

The reason why the code above uses a fixed IP address instead of fully qualified domain name (FQDN) is because a FQDN would require a DNS lookup. When the machine does not have a working internet connection, the DNS lookup itself may block the call to urllib_request.urlopen for more than a second. Thanks to @rzetterberg for pointing this out.


If the fixed IP address above is not working, you can find a current IP address for google.com (on unix) by running

% dig google.com  +trace ...google.com.     300 IN  A   216.58.192.142


If we can connect to some Internet server, then we indeed have connectivity. However, for the fastest and most reliable approach, all solutions should comply with the following requirements, at the very least:

  • Avoid DNS resolution (we will need an IP that is well-known and guaranteed to be available for most of the time)
  • Avoid application layer connections (connecting to an HTTP/FTP/IMAP service)
  • Avoid calls to external utilities from Python or other language of choice (we need to come up with a language-agnostic solution that doesn't rely on third-party solutions)

To comply with these, one approach could be to, check if one of the Google's public DNS servers is reachable. The IPv4 addresses for these servers are 8.8.8.8 and 8.8.4.4. We can try connecting to any of them.

A quick Nmap of the host 8.8.8.8 gave below result:

$ sudo nmap 8.8.8.8Starting Nmap 6.40 ( http://nmap.org ) at 2015-10-14 10:17 ISTNmap scan report for google-public-dns-a.google.com (8.8.8.8)Host is up (0.0048s latency).Not shown: 999 filtered portsPORT   STATE SERVICE53/tcp open  domainNmap done: 1 IP address (1 host up) scanned in 23.81 seconds

As we can see, 53/tcp is open and non-filtered. If you are a non-root user, remember to use sudo or the -Pn argument for Nmap to send crafted probe packets and determine if a host is up.

Before we try with Python, let's test connectivity using an external tool, Netcat:

$ nc 8.8.8.8 53 -zvConnection to 8.8.8.8 53 port [tcp/domain] succeeded!

Netcat confirms that we can reach 8.8.8.8 over 53/tcp. Now we can set up a socket connection to 8.8.8.8:53/tcp in Python to check connection:

import socketdef internet(host="8.8.8.8", port=53, timeout=3):    """    Host: 8.8.8.8 (google-public-dns-a.google.com)    OpenPort: 53/tcp    Service: domain (DNS/TCP)    """    try:        socket.setdefaulttimeout(timeout)        socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))        return True    except socket.error as ex:        print(ex)        return Falseinternet()

Another approach could be to send a manually crafted DNS probe to one of these servers and wait for a response. But, I assume, it might prove slower in comparison due to packet drops, DNS resolution failure, etc. Please comment if you think otherwise.

UPDATE #1: Thanks to @theamk's comment, timeout is now an argument and initialized to 3s by default.

UPDATE #2: I did quick tests to identify the fastest and most generic implementation of all valid answers to this question. Here's the summary:

$ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo'defos.pyTrue00:00:00:00.487iamaziz.pyTrue00:00:00:00.335ivelin.pyTrue00:00:00:00.105jaredb.pyTrue00:00:00:00.533kevinc.pyTrue00:00:00:00.295unutbu.pyTrue00:00:00:00.5467h3rAm.pyTrue00:00:00:00.032

And once more:

$ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo'defos.pyTrue00:00:00:00.450iamaziz.pyTrue00:00:00:00.358ivelin.pyTrue00:00:00:00.099jaredb.pyTrue00:00:00:00.585kevinc.pyTrue00:00:00:00.492unutbu.pyTrue00:00:00:00.4857h3rAm.pyTrue00:00:00:00.035

True in the above output signifies that all these implementations from respective authors correctly identify connectivity to the Internet. Time is shown with milliseconds resolution.

UPDATE #3: Tested again after the exception handling change:

defos.pyTrue00:00:00:00.410iamaziz.pyTrue00:00:00:00.240ivelin.pyTrue00:00:00:00.109jaredb.pyTrue00:00:00:00.520kevinc.pyTrue00:00:00:00.317unutbu.pyTrue00:00:00:00.4367h3rAm.pyTrue00:00:00:00.030


It will be faster to just make a HEAD request so no HTML will be fetched.
Also I am sure google would like it better this way :)

try:    import httplibexcept:    import http.client as httplibdef have_internet():    conn = httplib.HTTPConnection("www.google.com", timeout=5)    try:        conn.request("HEAD", "/")        conn.close()        return True    except:        conn.close()        return False