I want to see if I can access an online API, but for that I need to have Internet access.
How can I see if there's a connection available and active using Python?
Perhaps you could use something like this:
import urllib2 def internet_on(): try: urllib2.urlopen('http://188.8.131.52', timeout=1) return True except urllib2.URLError as err: return False
Currently, 184.108.40.206 is one of the IP addresses for google.com. Change
http://220.127.116.11 to whatever site can be expected to respond quickly.
This fixed IP will not map to google.com forever. So this code is not 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 18.104.22.168
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:
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
22.214.171.124. We can try connecting to any of them.
A quick Nmap of the host
126.96.36.199 gave below result:
$ sudo nmap 188.8.131.52 Starting Nmap 6.40 ( http://nmap.org ) at 2015-10-14 10:17 IST Nmap scan report for google-public-dns-a.google.com (184.108.40.206) Host is up (0.0048s latency). Not shown: 999 filtered ports PORT STATE SERVICE 53/tcp open domain Nmap done: 1 IP address (1 host up) scanned in 23.81 seconds
As we can see, TCP/53 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 host is up.
Before we try with Python, let's test connectivity using an external tool, Netcat:
$ nc 220.127.116.11 53 -zv Connection to 18.104.22.168 53 port [tcp/domain] succeeded!
Netcat confirms that we can reach
22.214.171.124 over TCP/53. Now we can set up a socket connection to 126.96.36.199:53/TCP in Python to check connection:
import socket def internet(host="188.8.131.52", port=53, timeout=3): """ Host: 184.108.40.206 (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 False internet()
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.py True 00:00:00:00.487 iamaziz.py True 00:00:00:00.335 ivelin.py True 00:00:00:00.105 jaredb.py True 00:00:00:00.533 kevinc.py True 00:00:00:00.295 unutbu.py True 00:00:00:00.546 7h3rAm.py True 00:00:00:00.032
And once more:
$ ls *.py | sort -n | xargs -I % sh -c 'echo %; ./timeit.sh %; echo' defos.py True 00:00:00:00.450 iamaziz.py True 00:00:00:00.358 ivelin.py True 00:00:00:00.099 jaredb.py True 00:00:00:00.585 kevinc.py True 00:00:00:00.492 unutbu.py True 00:00:00:00.485 7h3rAm.py True 00: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.py True 00:00:00:00.410 iamaziz.py True 00:00:00:00.240 ivelin.py True 00:00:00:00.109 jaredb.py True 00:00:00:00.520 kevinc.py True 00:00:00:00.317 unutbu.py True 00:00:00:00.436 7h3rAm.py True 00:00:00:00.030