Vérification de la connexion réseau


133

Je veux voir si je peux accéder à une API en ligne, mais pour cela, je dois avoir accès à Internet.

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


si vous êtes en python, il lèvera presque certainement une exception en cas d'échec de connexion ou d'expiration du délai. Vous pouvez essayer / attraper autour de cela, ou simplement le laisser faire surface.
jdizzle

1
@Triptych: J'espère que c'était une blague, car cela ne fonctionne pas
inspectorG4dget

1
@ inspectorG4dget:easy_install system_of_tubes
S.Lott

2
@aF: Regardez la solution d'Unutbu. Il montre (de la manière la plus rapide possible) comment vérifier si vous pouvez accéder à google.com. Si votre problème concerne l'accès à l'API, pourquoi ne pas essayer d'y accéder, en définissant timeout = 1? Cela vous dira exactement si l'API à laquelle vous souhaitez accéder est accessible. Une fois que vous le savez, vous pouvez continuer et accéder à l'API ou attendre un moment où vous pourrez y accéder.
inspectorG4dget

Comme je l'ai dit, j'avais juste besoin d'une chose simple comme le dit unutbu. Vous n'avez pas besoin de faire une telle histoire avec ça ..
aF.

Réponses:


132

Vous pourriez peut-être 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.142pour n'importe quel site susceptible de répondre rapidement .

Cette adresse IP fixe ne correspondra pas à google.com pour toujours. Donc, ce code n'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 (FQDN) est qu'un FQDN 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 urllib_request.urlopenpendant 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

1
Juste une note sur le "l'appel à urlopenne prendra pas beaucoup plus de 1 seconde même si Internet n'est pas" on "." - devis. Ce n'est pas vrai si l'url fournie n'est pas valide, la recherche DNS se bloquera. Cela n'est vrai que pour la connexion réelle au serveur Web. Le moyen le plus simple d'éviter ce bloc de recherche DNS est d'utiliser l'adresse IP à la place, alors il est garanti que cela ne prendra qu'une seconde :)
rzetterberg

8
CELA NE FONCTIONNE PLUS. Depuis septembre 2013, 74.125.113.99 expire après une longue période, donc cette fonction retournera toujours False. Je suppose que Google a changé leur réseau est mis en place.
theamk

4
Maintenant, le reste est simple. Google pour "74.125.113.99 urllib". Il renverra des milliers de projets open source qui ont incorporé le code incorrect. (pour moi, seule la première page contient au moins 5: nvpy, sweekychebot, malteseDict, upy, checkConnection). Ils sont tous brisés maintenant.
theamk le

4
Si ce n'est pas clair, JE NE RECOMMANDE PAS d'utiliser cette méthode. L'ancienne IP était bonne pendant moins de 3 ans. La nouvelle IP fonctionne aujourd'hui. Mettez-le dans votre projet, et il pourrait mystérieusement se briser dans moins de 3 ans, encore une fois.
theamk

1
Euh ... ouvrez simplement http://google.comet ensuite vous résolvez tous les problèmes dont tout le monde parle ici. Il n'est pas nécessaire d'utiliser une adresse IP ...
Jason C

106

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

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

Pour s'y conformer, une approche 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.8et 8.8.4.4. Nous pouvons essayer de nous connecter à l'un d'entre eux.

Un rapide Nmap de l'hôte a 8.8.8.8donné 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 voir, 53/tcpest ouvert et non filtré. Si vous êtes un utilisateur non root, n'oubliez pas d'utiliser sudoou l' -Pnargument pour Nmap pour envoyer des paquets de sonde spécialement conçus et déterminer si un 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.8plus 53/tcp. Nous pouvons maintenant configurer une connexion socket 8.8.8.8:53/tcpen 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 socket.error as ex:
        print(ex)
        return False

internet()

Une autre approche pourrait consister à envoyer une sonde DNS construite manuellement à l'un de ces serveurs et à attendre une réponse. Mais, je suppose, cela pourrait s'avérer plus lent en comparaison en raison de pertes de paquets, d'un échec de résolution DNS, etc. Veuillez commenter si vous pensez le contraire.

UPDATE # 1: Grâce au commentaire de @ theamk, timeout est maintenant un argument et initialisé 3spar 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

Truedans la sortie ci-dessus signifie que toutes ces implémentations des auteurs respectifs identifient correctement la connectivité à Internet. L'heure est affichée 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

6
C'est la meilleure réponse, en évitant la résolution DNS et, ironiquement, en consultant le service DNS de Google sur le port 53.
m3nda

1
@AviMehenwal Google fournit cette adresse IP dans le cadre de son service gratuit de résolution de noms DNS. L'IP n'est pas censée changer à moins que Google n'en décide autrement. Je l'utilise comme serveur DNS alternatif depuis quelques années maintenant sans aucun problème.
7h3rAm

1
@Luke Merci d'avoir signalé cela. J'ai mis à jour la réponse pour informer les utilisateurs de l'exception et renvoyer False comme réponse par défaut.
7h3rAm

2
@JasonC La connexion à TCP / 53 est différente de la connexion DNS sur le port 53. Selon votre analogie, chaque port TCP utilisé par une application sera classé comme connexion de protocole de niveau application. Non ce n'est pas vrai. La connexion via un socket TCP à un port N'EST PAS une connexion de niveau application. Je ne fais pas de recherche DNS, mais plutôt une poignée de main demi-TCP. Ce n'est pas la même chose que de faire une recherche DNS complète.
7h3rAm

2
Ne devrions-nous pas appeler close()la prise?
brk

60

Il sera plus rapide de simplement faire une requête HEAD afin qu'aucun HTML ne soit récupéré.
De plus, je suis sûr que Google aimerait mieux de cette façon :)

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

8
Ne prend que 20 milli secondes tandis que la réponse du haut prend 1 seconde.
Wally

8
+1 Cela n'a aucun sens de télécharger la page entière si vous voulez seulement vérifier si le serveur est accessible et répond. Téléchargez le contenu si vous avez besoin du contenu
thatsIch

Pour aucune raison, l'utilisation de l'url «8.8» fonctionne toujours, ce qui, évidemment, «8.8» ou « 8.8 » ne fonctionne pas dans un vrai navigateur Web.
Polv

2 heures à la recherche d'une solution de travail et puis j'ai trouvé ça ... propre et simple
Pedro Serpa

21

Comme alternative aux réponses ubutnu / Kevin C, j'utilise le requestspackage 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 pings 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

1
Request est une excellente bibliothèque. Cependant, contrairement à de nombreux exemples ici, j'utiliserais example.com ou example.org de l'IANA comme choix à long terme plus fiable car il est entièrement contrôlé par l' ICANN .
chirale

Existe-t-il un autre moyen de vérifier l'état de fonctionnement d'Internet. Parce que si vous vous languis google.comà nouveau, ils bloqueront notre adresse IP. Alors, y a-t-il un autre moyen.?
Sanjiv

15

Juste pour mettre à jour ce que unutbu a dit 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 mettrais probablement une référence à http: / /www.naver.com .


J'attendrai 30 secondes s'il n'y a pas de serveur DNS disponible.
Viktor Joras

10

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.

En gros, vous ne pouvez pas vérifier si l'ordinateur est connecté à Internet. Il peut y avoir de nombreuses raisons d'échec, comme une mauvaise configuration DNS, des pare-feu, NAT. Donc, même si vous effectuez des tests, vous ne pouvez pas avoir la garantie que vous serez connecté à votre API avant d'essayer.


2
"Il est plus facile de demander pardon que la permission"
cobbal

cela n'a pas besoin d'être aussi bon. J'ai simplement besoin d'essayer de me connecter à un site ou de cingler quelque chose et si cela donne du temps, voilá. Comment puis je faire ça?
aF.

Y a-t-il une raison pour laquelle vous ne pouvez pas simplement essayer de vous connecter à l'API? Pourquoi devez-vous le vérifier avant une vraie connexion?
Tomasz Wysocki

Je crée une page html en utilisant python. La page html dépend des arguments que je donne dans le programme python. Je n'ai besoin de mettre du code html que si je peux accéder à l'API. C'est pourquoi j'ai besoin de savoir avant.
aF.

6
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)


4

Essayez malgré tout l'opération que vous tentiez de faire. En cas d'échec, python devrait vous lancer une exception pour vous en informer.

Essayer d'abord une opération triviale pour détecter une connexion introduira une condition de concurrence. Que se passe-t-il si la connexion Internet est valide lorsque vous testez mais tombe en panne avant que vous n'ayez besoin d'effectuer un travail réel?


3

Cela peut ne pas fonctionner si l'hôte local a été modifié depuis 127.0.0.1 Try

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 modification, l'adresse IP de votre ordinateur sera 127.0.0.1 lorsqu'elle n'est pas connectée à 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 pourra aider


C'est une vérification intéressante, bien qu'elle n'identifie que si vous êtes connecté à un réseau. Que ce soit Internet ou un sous-réseau NAT restera une question.
7h3rAm

@ 7h3rAm, c'est un bon point, le DCHP ne nécessite pas de connexion Internet, mon erreur.

Cela nécessite simplement une connexion NIC réseau qui a reçu une adresse IP. Contrairement à toutes les autres réponses, il ne nécessite pas de connexion au LAN, routeur, pare-feu, FAI jusqu'à un autre système. Il ne parvient toujours pas à montrer que le NIC est connecté s'il s'agit d'une adresse non affectée par DHCP (statique)
user150471

@ user150471, déjà souligné, merci pour votre contribution.

3

Voici ma version

import requests

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

1
J'aime celui-ci, mais ce serait mieux s'il excluait un délai d'expiration ou une erreur de connexion spécifique généré par les demandes. Tel quel, un Ctrl-C ultra-rapide s'imprimera hors ligne.
user2561747

2

Une solution portable moderne avec requests:

import requests

def internet():
    """Detect an internet connection."""

    connection = None
    try:
        r = requests.get("https://google.com")
        r.raise_for_status()
        print("Internet connection detected.")
        connection = True
    except:
        print("Internet connection not detected.")
        connection = False
    finally:
        return connection

Ou, une version qui lève une exception:

import requests
from requests.exceptions import ConnectionError

def internet():
    """Detect an internet connection."""

    try:
        r = requests.get("https://google.com")
        r.raise_for_status()
        print("Internet connection detected.")
    except ConnectionError as e:
        print("Internet connection not detected.")
        raise e

1

Le meilleur moyen de le faire est de le faire vérifier par rapport à une adresse IP que Python donne toujours s'il ne trouve pas le site Web. Dans ce cas, voici 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

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

cela fonctionne tranquillement, sans rien télécharger mais en vérifiant que le fichier distant donné existe sur le Web


0

Prenant la réponse d'unutbu comme point de départ, et ayant été gravé dans le passé par un changement d'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 répondant pour une utilisation lors de vérifications ultérieures. De cette façon, l'adresse IP est toujours à jour (en supposant que la classe est réinitialisée au moins une fois tous les quelques années environ). Je remercie également gawry pour cette réponse , qui m'a montré comment obtenir l'adresse IP du serveur (après toute redirection, etc.). Veuillez ne pas tenir compte du piratage apparent de cette solution, je vais ici pour un exemple de travail minimal. :)

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

En prenant la réponse de Six, je pense que nous pourrions simplifier d'une manière ou d'une autre, une question importante car les nouveaux arrivants sont perdus dans des questions hautement 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)       

fonctionnement maximum: 5 minutes si atteint, j'essaierai dans une heure mais c'est un autre morceau de script!


votre essai var ne s'habitue pas, n'est-ce pas?
kidCoder

0

Prenant la réponse d'Ivelin et ajoutez une vérification supplémentaire car mon routeur fournit son adresse IP 192.168.0.1 et renvoie une tête s'il n'a pas de connexion Internet lors de l'interrogation de google.com.

import socket

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

Cela fonctionne pour moi en 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

J'en ai ajouté quelques-uns au code de Joel.

    import socket,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

0

Pour mes projets, j'utilise un script modifié pour envoyer une requête ping au serveur DNS public de google 8.8.8.8. Utilisation d'un délai d'expiration de 1 seconde et des bibliothèques python principales sans dépendances externes:

import struct
import socket
import select


def send_one_ping(to='8.8.8.8'):
   ping_socket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname('icmp'))
   checksum = 49410
   header = struct.pack('!BBHHH', 8, 0, checksum, 0x123, 1)
   data = b'BCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwx'
   header = struct.pack(
      '!BBHHH', 8, 0, checksum, 0x123, 1
   )
   packet = header + data
   ping_socket.sendto(packet, (to, 1))
   inputready, _, _ = select.select([ping_socket], [], [], 1.0)
   if inputready == []:
      raise Exception('No internet') ## or return False
   _, address = ping_socket.recvfrom(2048)
   print(address) ## or return True


send_one_ping()

La valeur du délai de sélection est 1, mais peut être un nombre à virgule flottante de choix pour échouer plus facilement que 1 seconde dans cet exemple.


0

importez les demandes et essayez ce simple code python.

def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
    _ = requests.get(url, timeout=timeout)
    return True
except requests.ConnectionError:
return False
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.