53

I have the following code that checks if an internet connection is present.

import urllib2

def internet_on():
    try:
        response=urllib2.urlopen('http://74.125.228.100',timeout=20)
        return True
    except urllib2.URLError as err: pass
    return False

This will test for an internet connection, but how effective is it?

I know internet varies in quality from person to person, so I'm looking for something that is most effective for the broad spectrum, and the above code seems like there might be loopholes where people could find bugs. For instance if someone just had a really slow connection, and took longer than 20 seconds to respond.

Kara
  • 6,115
  • 16
  • 50
  • 57
Joshua Strot
  • 2,343
  • 4
  • 26
  • 33
  • Why? As asked, this sounds like a straightforward example of "look before you leap." A better approach is usually "it's easy to ask forgiveness than permission." If you explain what you're trying to accomplish you might get better answers. – Jean-Paul Calderone Feb 15 '14 at 01:24
  • @Jean-PaulCalderone I'm trying to make sure the user has an internet connection, before a program of mine starts performing some tasks that will update the system. Such as download packages from a mirror, and then installing them. – Joshua Strot Feb 15 '14 at 15:58
  • 3
    Why don't you just try downloading those packages? If the connection attempt to the mirror times out then you can report the timeout to the user. The user will *vastly* prefer this experience to your buggy attempt to detect if their network is working. – Jean-Paul Calderone Feb 16 '14 at 01:37

24 Answers24

80

My approach would be something like this:

import socket
REMOTE_SERVER = "one.one.one.one"
def is_connected(hostname):
  try:
    # See if we can resolve the host name - tells us if there is
    # A DNS listening
    host = socket.gethostbyname(hostname)
    # Connect to the host - tells us if the host is actually reachable
    s = socket.create_connection((host, 80), 2)
    s.close()
    return True
  except Exception:
     pass # We ignore any errors, returning False
  return False
%timeit is_connected(REMOTE_SERVER)
> 31.9 ms ± 627 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

This will return within less than a second if there is no connection (Linux, Python 3.8).

Note: This test can return false positives - e.g. the DNS lookup may return a server within the local network. To be really sure you are connected to the internet, and talking to a valid host, be sure to use more sophisticated methods (e.g. SSL).

miraculixx
  • 10,034
  • 2
  • 41
  • 60
  • 2
    That does seem to be a better approach. – Joshua Strot Jan 03 '14 at 23:16
  • 2
    What if the user has added www.google.com to their /etc/hosts file? What if they're running a local caching nameserver or are on a LAN with a caching nameserver nearby? What if they are "connected to the internet" but traffic isn't actually being routed properly? There are lots of ways for this to fail. – Jean-Paul Calderone Feb 15 '14 at 01:26
  • 2
    @Jean-PaulCalderone fair point, included an actual connection test and a respective comment. Feel free to improve the answer if you see fit – miraculixx Feb 15 '14 at 11:57
  • This is nice, but it's a blocking method. Is there any easy way to convert to use asyncio coroutines? – ZioByte Feb 02 '19 at 19:55
  • Is there any update on this answer for windows? Since this answer is 5 years old from now. I tried to use this one but I am having this: `No connection could be made because the target machine actively refused it` even when I tried this with `localhost`. – Code_Ninja Apr 19 '19 at 03:39
  • Is there any other way to check internet running status. Because if you pining `google.com` again again, then they will block our IP. So Is there any other way.? – Sanjiv Aug 21 '19 at 08:29
  • @Sanjiv you can use any hostname/webserver that you like, I just used google.com as an example. If you do this continuously you should limit the number of connections made per time period. – miraculixx Aug 21 '19 at 16:29
  • 5
    don't use `google.com` instead use `1.1.1.1`, it will always be up, its faster and is less of a privacy concern. `1.1.1.1` is a DNS server and needs to stay up. `1.1.1.1` can also be accessed through `one.one.one.one` – Harry S Mar 05 '20 at 16:35
  • @HarryS thanks for the hint, updated answer accordingly. Good thinking – miraculixx Mar 06 '20 at 08:53
  • Does this work behind a corporate proxy ? I have doubts. Probably the DNS part yes, but not the `create_connection` one. The best approach in that case would probably be to use only `gethostbyname`, or to rely on e.g. `requests.get` as suggested below to use the proxy settings (if correctly set of course) – smarie Apr 21 '20 at 06:21
  • 1
    @smarie depending on the type of proxy you could use requests or something like [PySocks](https://pypi.org/project/PySocks/) – miraculixx Apr 21 '20 at 11:10
  • Hey @miraculixx just saying you probably shouldn't use `except:`, rather `except Exception:` just in case a BaseException is raised like keyboardinterrupt – Anony Mous May 13 '22 at 06:14
38

As of Python 2.6 and newer (including Python 3), a more straightforward solution which is also compatible with IPv6 would be

import socket


def is_connected():
    try:
        # connect to the host -- tells us if the host is actually
        # reachable
        socket.create_connection(("1.1.1.1", 53))
        return True
    except OSError:
        pass
    return False

It resolves the name and tries to connect to each return addres before concluding it is offline. This also includes IPv6 addresses.

Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
andrebrait
  • 497
  • 4
  • 8
  • 2
    Thank you for this solution – Ievgen Jan 30 '18 at 13:59
  • I'd probably check other ports too, such as 443 for websites, but also 21 for known ftp sites or some dns servers for example, and perhaps ping some well known ip addresses, just in case dns is cached or blocked... – KolonUK Apr 03 '19 at 09:29
8

Efficient way to check internet availability (modified @andrebrait's answer).

import socket

def isConnected():
    try:
        # connect to the host -- tells us if the host is actually
        # reachable
        sock = socket.create_connection(("www.google.com", 80))
        if sock is not None:
            print('Clossing socket')
            sock.close
        return True
    except OSError:
        pass
    return False
vvvvv
  • 25,404
  • 19
  • 49
  • 81
Pampapathi
  • 317
  • 3
  • 12
3

I have been using this for a while now, works fine

import time
import requests 
while True:
    try:
        requests.get('https://www.google.com/').status_code
        break
    except:
        time.sleep(5)
        pass
gala
  • 64
  • 1
  • 5
  • Is there any event handler we can use instead of while loop . btw, does a while loop hurts ? – Amit Bravo Aug 14 '21 at 12:38
  • The while loop here stops any other things the program is currently doing, so I would use `await asyncio.sleep()` which you have to import as well as `time`. Also you don't need the `.status_code` as you only want to check if the host is reachable. The rest seems so far good (didn't test it though) – FileX Sep 07 '21 at 08:54
  • @FlexGames well you are correct, but it kinda depends on the situation in a lot of scripts i need to stop the execution till the net connection is established so i just use a `while` loop – gala Sep 08 '21 at 05:09
3

Here's a script that I use on Windows to continuously monitors the connectivity. Prints in green/red and also reduces wait time when there is loss of connectivity.

from datetime import datetime
import time, os, requests
from termcolor import colored

os.system('color')
url = 'https://www.google.com/'
timeout = 2
sleep_time = 10
op = None

while True:
    now = datetime.now()
    try:
        op = requests.get(url, timeout=timeout).status_code
        if op == 200:
            print(now, colored("Connected", "green"))
            sleep_time = 10
        else:
            print(now, colored("Status Code is not 200", "red"))
            print("status Code", op)
    except:
        print(now, colored("Not Connected", "red"))
        print("status Code", op)
        sleep_time = 5
    time.sleep(sleep_time)
scorpi03
  • 69
  • 3
1

this will work

import urllib
try :
    stri = "https://www.google.co.in"
    data = urllib.urlopen(stri)
    print "Connected"
except e:
    print "not connected" ,e 
  • 7
    This is bad way! Because you load whole page! You don't need this! – Ievgen Jan 30 '18 at 14:00
  • 1
    @Ievgen Is there any other way to check internet running status. Because if you pining `google.com` again again, then they will block our IP. So Is there any other waya.? – Sanjiv Aug 21 '19 at 08:29
1

To complement miraculixx's answer ; Many situations can happen

  1. The user has no network adapter or no connection to a network. This can be detected with DNS resolution failing (socket.gethostbyname)

  2. The user is connected to a local network with direct internet access (no DNS proxy, no TCP/HTTP proxy). In that case the DNS resolution failing (socket.gethostbyname) will also indicate loss of connection to internet

  3. The user is connected to a local network where a DNS proxy is present but no TCP/HTTP(s) proxy is needed to access the internet. In that case DNS resolution success is not enough to indicate connection to the internet, an HTTP query (or at least opening a TCP session on the HTTP(s) port) is needed: socket.create_connection

  4. The user is connected to a local network where a TCP/HTTP(s) proxy is needed to access the internet. In that case socket.create_connection will fail as the TCP socket needs to point to the proxy, not to the end host. You can get the current proxy configuration using urllib.getproxies (python 2) or urllib.request.getproxies (python 3). So after identifying the proxy info using urllib.parse.urlparse you can use urllib of - much easier - requests to establish an HTTP GET to some known url.

However, this last method can fail (indicate no connection while there is actually one) if the user has not configured the proxy in the OS environment variables used by urllib or requests and rather configures his tools one by one (for example conda using the .condarc proxy_servers section). In that case there is no magic way to detect if the failure comes from a wrong proxy configuration or a loss of internet connection - except inspecting the proxy configuration files for the tool you wish to actually work for.

So as a conclusion,

  • a dns resolution failure is a reliable way to detect "has no internet access"
  • If you are sure that the user is not sitting behind a proxy (for example mobile apps), a failed/successful TCP session is a good way to detect "hasn't/has internet access)
  • Otherwise, a successful HTTP GET using requests is a good way to detect "has internet access" but failure is not sufficient to indicate anything.

See also this page for proxy-related configuration tricks.

smarie
  • 4,568
  • 24
  • 39
0

Http seems a too high level for checking network availability.

Nevertheless you can create a thread that check periodically the connectivity and store the connectivity state, next the internet_on method could just check the stored state. This will should be quicker than testing connectivity each time.

mpromonet
  • 11,326
  • 43
  • 62
  • 91
0

I wanted to test my internet connection in an infinite loop to monitor when my network goes up and down. I noticed the following: when my network was down and I started the monitoring script like that and the network came back, the script didn't notice it. The network was alive but the script didn't see that. When my network was on and I started the script like that, it noticed the changes. So I came up with the following solution that worked for me in both cases:

import shlex
from subprocess import call, PIPE, STDOUT

def get_return_code_of_simple_cmd(cmd, stderr=STDOUT):
    """Execute a simple external command and return its exit status."""
    args = shlex.split(cmd)
    return call(args, stdout=PIPE, stderr=stderr)

def is_network_alive():
    cmd = "ping -c 1 www.google.com"
    return get_return_code_of_simple_cmd(cmd) == 0

Here we rely on an external program (ping) that is independent from our script.

Jabba
  • 19,598
  • 6
  • 52
  • 45
0

Though the answer has been ticked, it couldn't help me, I had getting an error like

urllib2 is undefined

so I had tried to install urllib2 library using pip but was helpless then I dig up around and luckily I got a solution please check following code, sharing because someone who will face problem that I had before, will get the solution

from urllib.request import urlopen

def is_internet_available():
    try:
        urlopen('http://216.58.192.142', timeout=1)
        return True
    except:
        return False


print(is_internet_available())
Viraj Mohite
  • 308
  • 1
  • 13
0

Whether internet is connected or not can be indirectly known by fetching the present date from NTP server .

import ntplib
import datetime, time
    

try:

    client = ntplib.NTPClient()
    response = client.request('pool.ntp.org')
    Internet_date_and_time = datetime.datetime.fromtimestamp(response.tx_time)  
    print('\n')
    print('Internet date and time as reported by server: ',Internet_date_and_time)


except OSError:

    print('\n')
    print('Internet date and time could not be reported by server.')
    print('There is not internet connection.')
    
Ranjan Pal
  • 307
  • 3
  • 13
0

We can test internet connectivity within one line but, this method is inadvisable to use every time. Use this answer to learn about one line coding in python ;)

print((lambda a: 'Internet connected and working' if 0 == a.system('ping google.com -w 4 > clear') else 'Internet not connected.')(__import__('os')))

In the above code, the __import__ function will import the module in one line.

In the normal way:

import os
def check_internet():
    cmd = os.system('ping google.com -w 4 > clear')
    if cmd == 0:
        print('Internet is connected')
    else:
        print('Internet is not connected')

if __name__ == '__main__':
    check_internet()

Posting this question with the ❤️ of one line coding in python

  • This method will not work if ICMP requests are disabled. [see](https://stackoverflow.com/questions/13898961/what-could-cause-a-ping-to-fail-if-i-am-able-to-load-the-sites-homepage-in-a-br)! – Ayush Dec 07 '21 at 13:13
0

I have another solution. We have cmd command for checking connection: For example "netsh wlan show interface " this command in cmd gives us connection in and out speed. So you can use that in python:

from subprocess import check_output

output=check_output(['netsh','wlan','show','interface'])

output=str(output) #to convert byte to string

and then you can see the state of internet in the line started as Result:

... \r\n State : connected\r\n

then we can split it by '\r\n' character to extract the information we need or we can use Regular expression.

0

This is how we do it in our production:

import socket, sys

def ValidateConnection(host: str):
    try:
        DnsLookup: tuple = socket.gethostbyname_ex(host.strip())
        if DnsLookup[-1]:
            ipaddress: str = DnsLookup[-1][0]
            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
                sock.settimeout(1.0)
                result: int = sock.connect_ex((ipaddress,53))
                if result == 0:
                    return(True)
    except Exception as e:
        if "[Errno 11001] getaddrinfo failed" in str(e):
            print("Unable to lookup host: "+host)
        else:
            print("Unexpected error: "+str(e), sys.exc_info()[0])
    return(False)

Results:

print(ValidateConnection("this.does.not.exist"))
Unable to lookup host: this.does.not.exist
False

print(ValidateConnection("one.one.one.one"))
True

Python 3.9.9

Cow
  • 2,543
  • 4
  • 13
  • 25
0
import socket
import time
def is_connected():
    try:
        s  = socket.socket()
        s.connect(('google.com',443))
        s.close()
        return True
    except:
        return False

t=time.time()
if is_connected():
    print("connected")
else:
    print("no internet!")
print(time.time()-t)

0

In Python 3:

import socket

HOST_PORT = 80
HOST_NAME = "google.com"


def is_internet_connected(host_name: str, host_port: int):
    try:
        # Get Host IP Address
        host_ip = socket.gethostbyname(host_name)
        # Timeout: 5 Seconds
        timeout = 5
        # Try to connect
        client_socket = socket.create_connection(
            address=(host_ip, host_port), timeout=timeout
        )
        # Close the connection
        client_socket.close()
        return True
    except Exception:
        # Ignore any errors!
        pass
    return False


result = is_internet_connected(host_name=HOST_NAME, host_port=HOST_PORT)
print(result)
-1

This is what I use:

import subprocess

subprocess.call('ping -t 8.8.8.8')
  • 1
    Also, this only tests icmp - the users firewall may be allowing pings, but blocking http connections... – KolonUK Apr 03 '19 at 09:26
-1

I hope ,I can help problem with you.

import urllib
try :
    url = "https://www.google.com"
    urllib.urlopen(url)
    status = "Connected"
except :
    status = "Not connect"
print status
siczones
  • 9
  • 4
-1

I don't need the post on every time check...So I use to notify when device goes from online to offline and vice versa.

import socket
import time

mem1 = 0
while True:
    try:
        host = socket.gethostbyname(
            "www.google.com"
        )  # Change to personal choice of site
        s = socket.create_connection((host, 80), 2)
        s.close()
        mem2 = 1
        if mem2 == mem1:
            pass  # Add commands to be executed on every check
        else:
            mem1 = mem2
            print("Internet is working")  # Will be executed on state change

    except Exception as e:
        mem2 = 0
        if mem2 == mem1:
            pass
        else:
            mem1 = mem2
            print("Internet is down")
    time.sleep(10)  # timeInterval for checking
AMC
  • 2,642
  • 7
  • 13
  • 35
  • Using `except Exception as e:` like this is bad practice, see: https://stackoverflow.com/questions/54948548/what-is-wrong-with-using-a-bare-except, https://stackoverflow.com/questions/4990718/about-catching-any-exception. – AMC Feb 21 '20 at 19:38
-1

Here is my code, it's working fine.

 import requests
 try:
    requests.get('https://www.google.com/').status_code
    print("Connected")
 except:
    print("Not Connected")
    exit()
Md.Rakibuz Sultan
  • 759
  • 1
  • 8
  • 13
-1
import socket
IPaddress=socket.gethostbyname(socket.gethostname())
if IPaddress=="127.0.0.1":
    print("No internet, your localhost is "+ IPaddress)
else:
    print("Connected, with the IP address: "+ IPaddress )
  • 1
    This is not for check the internet is connected.Even if you connected to hotspot without internet the ipaddress will allocate for the device.ipaddress is for finding the path and it is for communication between router and device not for the internet. – NAGA RAJ S Dec 02 '20 at 10:25
-1

Use google to check connection since its the fastest website in the world and also work with slow networks as well

import urllib.request
    def connect():
        host='http://google.com'
        try:
            urllib.request.urlopen(host) #Python 3.x
            return True
        except:
            return False

it returns boolean True means Connection is Available and returns False means there is no Internet Connection

Vishal Barvaliya
  • 197
  • 1
  • 3
  • 14
-1

check internet using Python Request

import urllib
from urllib.request import urlopen


def is_internet():
    """
    Query internet using python
    :return:
    """
try:
    urlopen('https://www.google.com', timeout=1)
    return True
except urllib.error.URLError as Error:
    print(Error)
    return False


if is_internet():
    print("Internet is active")
else:
    print("Internet disconnected")
-3

Increase timeout to 30 seconds? Do multiple tries? Try few hosts?

Michał Tabor
  • 2,441
  • 5
  • 23
  • 30
  • Well, I was kind of hoping that someone might have an alternative code that worked better or had better error proofing. I only have a few people who can test my software, so if the problem doesn't show with them, it could very well go unknown to me. I could increase the timeout, but there's also people who have weird connections that can send requests, but can't hear back from them, so I want to leave the timeout still somewhat low... – Joshua Strot Jan 03 '14 at 22:13