web-dev-qa-db-fra.com

Vérification de la connexion réseau

Je veux voir si je peux accéder à une API en ligne, mais pour cela, j'ai besoin d'un accès à Internet.

Comment puis-je voir s'il existe une connexion disponible et active à l'aide de Python?

101
aF.

Peut-être que vous pourriez utiliser quelque chose comme ceci:

import urllib2

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

Actuellement, 216.58.192.142 est l’une des adresses IP de google.com. Changez http://216.58.192.142 en n’importe quel site susceptible de réagir rapidement

Cette adresse IP fixe ne mappera pas pour toujours à google.com. Donc, ce code est Pas robuste - il aura besoin d’une maintenance constante pour continuer à fonctionner. 

La raison pour laquelle le code ci-dessus utilise une adresse IP fixe au lieu d'un nom de domaine complet est due au fait qu'un nom de domaine complet nécessiterait une recherche DNS. Lorsque la machine ne dispose pas d'une connexion Internet fonctionnelle, la recherche DNS elle-même peut bloquer l'appel de urllib_request.urlopen pendant plus d'une seconde. Merci à @rzetterberg pour l'avoir signalé.


Si l'adresse IP fixe ci-dessus ne fonctionne pas, vous pouvez trouver une adresse IP actuelle pour google.com (sous Unix) en exécutant

% Dig google.com  +trace 
...
google.com.     300 IN  A   216.58.192.142
112
unutbu

Si nous pouvons nous connecter à un serveur Internet, nous avons effectivement une connectivité. Cependant, pour une approche rapide et fiable, toutes les solutions doivent au moins respecter les exigences suivantes:

  • Évitez la résolution DNS (nous aurons besoin d'une adresse IP connue et garantie d'être disponible la plupart du temps)
  • Evitez les connexions basées sur la couche application (connexion à un service HTTP/FTP/IMAP)
  • Évitez les appels aux utilitaires externes de Python ou d'un autre langage de votre choix (nous devons proposer une solution indépendante de la langue et ne faisant pas appel à des solutions tierces).

Pour se conformer à ces règles, une solution pourrait consister à vérifier si l’un des serveurs DNS publics de Google est accessible. Les adresses IPv4 de ces serveurs sont 8.8.8.8 et 8.8.4.4. Nous pouvons essayer de nous connecter à l’un d’eux.

Un rapide Nmap de l'hôte 8.8.8.8 a donné le résultat ci-dessous:

$ Sudo nmap 8.8.8.8

Starting Nmap 6.40 ( http://nmap.org ) at 2015-10-14 10:17 IST
Nmap scan report for google-public-dns-a.google.com (8.8.8.8)
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

Comme nous pouvons le constater, TCP/53 est ouvert et non filtré. Si vous êtes un utilisateur non-root, n'oubliez pas d'utiliser Sudo ou l'argument -Pn de Nmap pour envoyer des paquets de sonde conçus et déterminer si l'hôte est actif.

Avant d’essayer avec Python, testons la connectivité à l’aide d’un outil externe, Netcat:

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

Netcat confirme que nous pouvons atteindre 8.8.8.8 via TCP/53. Nous pouvons maintenant configurer une connexion de socket à 8.8.8.8:53/TCP en Python pour vérifier la connexion:

>>> import socket
>>>
>>> def 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 Exception as ex:
...     print ex.message
...     return False
...
>>> internet()
True
>>>

Une autre approche pourrait être d’envoyer une sonde DNS conçue manuellement à l’un de ces serveurs et d’attendre une réponse. Mais, je suppose, la comparaison pourrait s’avérer plus lente en raison de l’abandon de paquets, de l’échec de la résolution DNS, etc. Veuillez commenter si vous pensez le contraire.

UPDATE # 1: Grâce au commentaire de @ theamk, le délai d'attente est maintenant un argument et initialisé à 3 secondes par défaut.

MISE À JOUR # 2: J'ai fait des tests rapides pour identifier l'implémentation la plus rapide et la plus générique de toutes les réponses valides à cette question. Voici le résumé:

$ 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

Et encore une fois:

$ 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 dans la sortie ci-dessus signifie que toutes ces implémentations des auteurs respectifs identifient correctement la connectivité à Internet. Le temps est affiché avec une résolution en millisecondes.

UPDATE # 3: Testé à nouveau après le changement de gestion des exceptions:

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
73
7h3rAm

Il sera plus rapide de simplement faire une demande HEAD afin qu'aucun code HTML ne soit récupéré.
De plus, je suis sûr que Google aimerait que cela soit mieux ainsi:)

try:
    import httplib
except:
    import http.client as httplib

def have_internet():
    conn = httplib.HTTPConnection("www.google.com", timeout=5)
    try:
        conn.request("HEAD", "/")
        conn.close()
        return True
    except:
        conn.close()
        return False
46
Ivelin

Juste pour mettre à jour ce que dit unutbu pour le nouveau code dans Python 3.2

def check_connectivity(reference):
    try:
        urllib.request.urlopen(reference, timeout=1)
        return True
    except urllib.request.URLError:
        return False

Et, juste pour noter, l’entrée ici (référence) est l’URL que vous voulez vérifier: je suggère de choisir quelque chose qui se connecte rapidement là où vous vivez - c’est-à-dire que je vis en Corée du Sud, donc je ferais probablement référence à http : //www.naver.com .

16
Kevin C

En guise d'alternative aux réponses de ubutnu/Kevin C, j'utilise le paquetage requests comme ceci:

import requests

def connected_to_internet(url='http://www.google.com/', timeout=5):
    try:
        _ = requests.get(url, timeout=timeout)
        return True
    except requests.ConnectionError:
        print("No internet connection available.")
    return False

Bonus: cela peut être étendu à cette fonction qui ping un site web.

def web_site_online(url='http://www.google.com/', timeout=5):
    try:
        req = requests.get(url, timeout=timeout)
        # HTTP errors are not raised by default, this statement does that
        req.raise_for_status()
        return True
    except requests.HTTPError as e:
        print("Checking internet connection failed, status code {0}.".format(
        e.response.status_code))
    except requests.ConnectionError:
        print("No internet connection available.")
    return False
14
Def_Os

Vous pouvez simplement essayer de télécharger des données, et si la connexion échoue, vous saurez que quelque chose avec la connexion ne va pas bien.

En gros, vous ne pouvez pas vérifier si votre ordinateur est connecté à Internet. Il peut y avoir plusieurs raisons à un échec, comme une configuration DNS incorrecte, des pare-feu, des NAT. Ainsi, même si vous effectuez des tests, vous ne pouvez pas avoir l'assurance que vous aurez une connexion avec votre API jusqu'à ce que vous essayiez.

9
Tomasz Wysocki
import urllib

def connected(Host='http://google.com'):
    try:
        urllib.urlopen(Host)
        return True
    except:
        return False

# test
print( 'connected' if connected() else 'no internet!' )

Pour Python 3, utilisez urllib.request.urlopen(Host)

6
Aziz Alto

Essayez l'opération que vous tentiez de faire quand même. Si cela échoue, python devrait vous lancer une exception à vous faire savoir.

Essayer une opération triviale en premier pour détecter une connexion introduira une condition de concurrence critique. Que se passe-t-il si la connexion Internet est valide lorsque vous testez, mais tombe en panne avant que vous ne deviez travailler?

3
mluebke

La meilleure façon de le faire est de le vérifier par rapport à une adresse IP que python donne toujours s’il ne trouve pas le site Web. Dans ce cas, c'est mon code:

import socket

print("website connection checker")
while True:
    website = input("please input website: ")
    print("")
    print(socket.gethostbyname(website))
    if socket.gethostbyname(website) == "92.242.140.2":
        print("Website could be experiencing an issue/Doesn't exist")
    else:
        socket.gethostbyname(website)
        print("Website is operational!")
        print("")
1
lunar_kitsune

Voici ma version

import requests

try:
    if requests.get('https://google.com').ok:
        print("You're Online")
except:
    print("You're Offline")
1
Mujeeb Ishaque

Cela pourrait ne pas fonctionner si l'hôte local a été changé de 127.0.0.1 Essayez 

import socket
ipaddress=socket.gethostbyname(socket.gethostname())
if ipaddress=="127.0.0.1":
    print("You are not connected to the internet!")
else:
    print("You are connected to the internet with the IP address of "+ ipaddress )

Sauf s’il est modifié, l’IP de votre ordinateur sera 127.0.0.1 s’il n’est pas connecté à Internet . Ce code obtient essentiellement l’adresse IP puis demande s’il s’agit de l’adresse IP de l’hôte local . J'espère que cela vous aidera

1
Steven Parkling

En prenant la réponse de unutbu comme point de départ et ayant déjà été gravée par une adresse IP "statique", j'ai créé une classe simple qui vérifie une fois en utilisant une recherche DNS (c'est-à-dire, en utilisant l'URL " https://www.google.com "), puis stocke l'adresse IP du serveur qui répond pour une utilisation lors des vérifications suivantes. Ainsi, l’adresse IP est toujours à jour (en supposant que la classe soit réinitialisée au moins une fois tous les deux ou trois ans). Je donne également crédit à gawry pour cette réponse , qui m'a montré comment obtenir l'adresse IP du serveur (après toute redirection, etc.). S'il vous plaît, ne tenez pas compte de l'apparente complexité de cette solution, je vais vous donner un exemple de travail minimal ici. :)

Voici ce que j'ai

import socket

try:
    from urllib2 import urlopen, URLError
    from urlparse import urlparse
except ImportError:  # Python 3
    from urllib.parse import urlparse
    from urllib.request import urlopen, URLError

class InternetChecker(object):
    conn_url = 'https://www.google.com/'

    def __init__(self):
        pass

    def test_internet(self):
        try:
            data = urlopen(self.conn_url, timeout=5)
        except URLError:
            return False

        try:
            Host = data.fp._sock.fp._sock.getpeername()
        except AttributeError:  # Python 3
            Host = data.fp.raw._sock.getpeername()

        # Ensure conn_url is an IPv4 address otherwise future queries will fail
        self.conn_url = 'http://' + (Host[0] if len(Host) == 2 else
                                     socket.gethostbyname(urlparse(data.geturl()).hostname))

        return True

# Usage example
checker = InternetChecker()
checker.test_internet()
0
Jared B.

Cela fonctionne pour moi dans Python3.6

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")
0
Rajiv Sharma

En prenant la réponse d'Ivelin et en ajoutant une vérification supplémentaire, mon routeur communique son adresse IP 192.168.0.1 et renvoie un en-tête s'il n'a pas de connexion Internet lorsqu'il interroge google.com.

def haveInternet():
    try:
        # first check if we get the correct IP-Address or just the router's IP-Address
        info = socket.getaddrinfo("www.google.com", None)[0]
        ipAddr = info[4][0]
        if ipAddr == "192.168.0.1" :
            return False
    except:
        return False

    conn = httplib.HTTPConnection("www.google.com", timeout=5)
    try:
        conn.request("HEAD", "/")
        conn.close()
        return True
    except:
        conn.close()
        return False
0
monok

En prenant la réponse de Six, je pense que nous pourrions simplifier d’une manière ou d’une autre, un problème important car les nouveaux arrivants sont perdus dans des domaines très techniques.

Voici ce que je vais enfin utiliser pour attendre que ma connexion (3G, lente) soit établie une fois par jour pour ma surveillance PV.

Fonctionne sous Pyth3 avec Raspbian 3.4.2

from urllib.request import urlopen
from time import sleep
urltotest=http://www.lsdx.eu             # my own web page
nboftrials=0
answer='NO'
while answer=='NO' and nboftrials<10:
    try:
        urlopen(urltotest)
        answer='YES'
    except:
        essai='NO'
        nboftrials+=1
        sleep(30)       

course maximum: 5 minutes si atteint, j'essayerai dans une heure, mais c'est un autre script!

0
Seylione

mon préféré, lors de l'exécution de scripts sur un cluster ou non

import subprocess

def online(timeout):
    try:
        return subprocess.run(
            ['wget', '-q', '--spider', 'google.com'],
            timeout=timeout
        ).returncode == 0
    except subprocess.TimeoutExpired:
        return False

wget fonctionne silencieusement, ne télécharge rien mais vérifie que le fichier distant donné existe sur le Web

0
neok