Verifica della connessione di rete


133

Voglio vedere se posso accedere a un'API online, ma per questo ho bisogno di avere accesso a Internet.

Come posso vedere se c'è una connessione disponibile e attiva usando Python?


se sei in Python, quasi sicuramente genererà un'eccezione in caso di errore di connessione o timeout. Puoi provare / aggirarlo o lasciarlo emergere.
jdizzle,

1
@Triptych: spero che fosse uno scherzo, perché non funziona
inspectorG4dget

1
@ inspectorG4dget:easy_install system_of_tubes
S.Lott

2
@aF: guarda la soluzione di Unutbu. Mostra (nel modo più veloce possibile) come verificare se si è in grado di accedere a google.com. Se il tuo problema riguarda l'accesso all'API, allora perché non provare ad accedervi, impostando il timeout = 1? Questo ti dirà esattamente se l'API a cui vuoi accedere è accessibile. Una volta che lo sai, puoi andare avanti e accedere all'API o attendere un momento in cui puoi accedervi.
inspector

Come ho detto, avevo solo bisogno di una cosa semplice come disse unutbu. Non hai bisogno di fare tante storie con questo ...
aF.

Risposte:


132

Forse potresti usare qualcosa del genere:

import urllib2

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

Attualmente, 216.58.192.142 è uno degli indirizzi IP per google.com. Passare http://216.58.192.142a qualunque sito ci si può aspettare che risponda rapidamente .

Questo IP fisso non verrà mappato su google.com per sempre. Quindi questo codice non è robusto - avrà bisogno di una manutenzione costante per farlo funzionare.

Il motivo per cui il codice sopra riportato utilizza un indirizzo IP fisso anziché un nome di dominio completo (FQDN) è perché un nome di dominio completo richiede una ricerca DNS. Quando la macchina non ha una connessione Internet funzionante, la ricerca DNS stessa potrebbe bloccare la chiamata urllib_request.urlopenper più di un secondo. Grazie a @rzetterberg per averlo segnalato.


Se l'indirizzo IP fisso sopra non funziona, è possibile trovare un indirizzo IP corrente per google.com (su unix) eseguendo

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

1
Solo una nota sul "la chiamata a urlopennon richiederà molto più di 1 secondo anche se Internet non è" on "." - citazione. Ciò non è vero se l'URL fornito non è valido, quindi la ricerca DNS verrà bloccata. È vero solo per la connessione effettiva al web-server. Il modo più semplice per evitare questo blocco di ricerca DNS è utilizzare l'indirizzo IP, quindi è garantito solo 1 secondo :)
rzetterberg

8
QUESTO NON FUNZIONA PIÙ. A partire da settembre 2013, 74.125.113.99 scade dopo molto tempo, quindi questa funzione restituirà sempre False. Suppongo che Google abbia cambiato la loro rete è impostata.
theamk,

4
Ora il resto è semplice. Google per "74.125.113.99 urllib". Restituirà migliaia di progetti open source che incorporano il codice errato. (per me, solo la prima pagina contiene almeno 5: nvpy, sweekychebot, malteseDict, upy, checkConnection). Ora sono tutti rotti.
theamk,

4
Se non è chiaro, NON CONSIGLIO di utilizzare questo metodo. Il vecchio IP andava bene per meno di 3 anni. Il nuovo IP funziona oggi. Inseriscilo nel tuo progetto e potrebbe rompersi misteriosamente in meno di 3 anni.
theamk,

1
Ehm ... apri http://google.come poi risolvi tutti i problemi di cui tutti continuano a parlare qui. Non è necessario utilizzare un indirizzo IP ...
Jason C

106

Se siamo in grado di connetterci ad alcuni server Internet, allora abbiamo davvero la connettività. Tuttavia, per un approccio più rapido e affidabile, tutte le soluzioni devono soddisfare almeno i seguenti requisiti:

  • Evita la risoluzione DNS (avremo bisogno di un IP noto e garantito per la maggior parte del tempo)
  • Evita connessioni a livello di applicazione (connessione a un servizio HTTP / FTP / IMAP)
  • Evita le chiamate a programmi di utilità esterni da Python o altre lingue preferite (dobbiamo trovare una soluzione indipendente dalla lingua che non si basi su soluzioni di terze parti)

Per conformarsi a questi, un approccio potrebbe essere quello di verificare se uno dei server DNS pubblici di Google è raggiungibile. Gli indirizzi IPv4 per questi server sono 8.8.8.8e 8.8.4.4. Possiamo provare a collegarci a uno di essi.

Una rapida Nmap dell'host ha 8.8.8.8dato il risultato seguente:

$ 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

Come possiamo vedere, 53/tcpè aperto e non filtrato. Se sei un utente non root, ricorda di utilizzare sudoo l' -Pnargomento per Nmap per inviare pacchetti di probe predisposti e determinare se un host è attivo.

Prima di provare con Python, testiamo la connettività utilizzando uno strumento esterno, Netcat:

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

Conferma netcat che possono raggiungere 8.8.8.8oltre 53/tcp. Ora possiamo impostare una connessione socket su 8.8.8.8:53/tcpin Python per verificare la connessione:

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

Un altro approccio potrebbe essere quello di inviare un probe DNS creato manualmente a uno di questi server e attendere una risposta. Ma, suppongo, potrebbe rivelarsi più lento in confronto a causa di cadute di pacchetti, errori di risoluzione DNS, ecc. Si prega di commentare se si pensa diversamente.

AGGIORNAMENTO N. 1: Grazie al commento di @ theamk, il timeout è ora un argomento e inizializzato per 3simpostazione predefinita.

AGGIORNAMENTO # 2: ho eseguito test rapidi per identificare l'implementazione più rapida e generica di tutte le risposte valide a questa domanda. Ecco il riassunto:

$ 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

E ancora una volta:

$ 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

Truenell'output sopra indica che tutte queste implementazioni dei rispettivi autori identificano correttamente la connettività a Internet. Il tempo viene visualizzato con una risoluzione di millisecondi.

AGGIORNAMENTO # 3: testato di nuovo dopo la modifica della gestione delle eccezioni:

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
Questa è la risposta migliore, evitando la risoluzione DNS e, ironia della sorte, consultare il servizio DNS di Google sulla porta 53.
m3nda

1
@AviMehenwal Google fornisce questo IP nell'ambito del suo servizio gratuito di risoluzione dei nomi DNS. L'IP non dovrebbe cambiare a meno che Google non decida diversamente. Lo uso come server DNS alternativo da alcuni anni senza problemi.
7h3rAm

1
@Luke Grazie per averlo sottolineato. Ho aggiornato la risposta per informare gli utenti sull'eccezione e restituire False come risposta predefinita.
7h3rAm

2
@JasonC La connessione a TCP / 53 è diversa dalla connessione DNS sulla porta 53. Per analogia, ogni porta TCP utilizzata da un'applicazione verrà classificata come connessione protocollo a livello di applicazione. No non è vero. La connessione tramite un socket TCP a una porta NON È una connessione a livello di applicazione. Non sto effettuando una ricerca DNS, ma solo una stretta di mano mezzo TCP. Non è la stessa cosa che fare una ricerca DNS completa.
7h3r,

2
Non dovremmo chiamare close()sul socket?
Brk

60

Sarà più veloce fare una richiesta HEAD in modo che nessun HTML venga recuperato.
Inoltre sono sicuro che Google vorrebbe che fosse meglio così :)

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
Richiede solo 20 milli secondi mentre la risposta superiore richiede 1 secondo.
Wally,

8
+1 Non ha senso scaricare l'intera pagina se si desidera solo verificare se il server è raggiungibile e risponde. Scarica il contenuto se è necessario il contenuto
thatsIch

Per nessun motivo, l'utilizzo dell'URL '8.8' funziona ancora, che ovviamente '8.8' o ' 8.8 ' non funziona in un vero browser web.
Polv,

2 ore alla ricerca di una soluzione funzionante e poi ho trovato questo ... pulito e semplice
Pedro Serpa,

21

In alternativa alle risposte di ubutnu / Kevin C, uso il requestspacchetto in questo modo:

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: questo può essere esteso a questa funzione che esegue il ping di un sito 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
La richiesta è un'ottima biblioteca. Tuttavia, a differenza di molti esempi qui, utilizzerei example.com o example.org di IANA come una scelta più affidabile a lungo termine poiché è completamente controllata da ICANN .
Chirale,

Esiste un altro modo per controllare lo stato di funzionamento di Internet. Perché se ripeti di google.comnuovo, allora bloccheranno il nostro IP. Quindi c'è un altro modo.
Sanjiv,

15

Solo per aggiornare ciò che unutbu ha detto per il nuovo codice in Python 3.2

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

E, solo per notare, l'input qui (riferimento) è l'URL che vuoi controllare: ti suggerisco di scegliere qualcosa che si collega velocemente dove vivi - cioè vivo in Corea del Sud, quindi probabilmente definirei riferimento a http: / /www.naver.com .


Aspetterò 30 secondi se non è disponibile un server DNS.
Viktor Joras,

10

Puoi semplicemente provare a scaricare i dati e se la connessione fallisce saprai che qualcosa con la connessione non va bene.

Fondamentalmente non è possibile verificare se il computer è connesso a Internet. Ci possono essere molti motivi di errore, come configurazione DNS, firewall e NAT errati. Quindi, anche se fai alcuni test, non puoi avere la garanzia che avrai una connessione con la tua API fino a quando non provi.


2
"È più facile chiedere perdono che permesso"
cobbal

questo non deve essere così buono. Ho semplicemente bisogno di provare a connettermi a un sito o eseguire il ping di qualcosa e se dà timeout voilá. Come lo posso fare?
aF.

C'è qualche motivo per cui non puoi semplicemente provare a connetterti all'API? Perché è necessario verificarlo prima della connessione reale?
Tomasz Wysocki,

Faccio una pagina html usando Python. La pagina html dipende dagli argomenti che fornisco nel programma Python. Ho solo bisogno di mettere un po 'di codice HTML se posso accedere all'API. Ecco perché devo sapere prima.
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!' )

Per python 3, utilizzare urllib.request.urlopen(host)


4

Prova comunque l'operazione che stavi tentando di fare. Se fallisce, Python dovrebbe generare un'eccezione per informarti.

Per provare prima qualche operazione banale per rilevare una connessione, verrà introdotta una condizione di competizione. Cosa succede se la connessione Internet è valida quando si esegue il test ma si interrompe prima di dover eseguire il lavoro effettivo?


3

Questo potrebbe non funzionare se localhost è stato modificato da 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 )

Se non modificato, l'IP del tuo computer sarà 127.0.0.1 quando non è connesso a Internet. Questo codice ottiene sostanzialmente l'indirizzo IP e quindi chiede se si tratta dell'indirizzo IP localhost. spero che aiuti


È un controllo interessante, anche se identificherà solo se sei connesso a una rete. Se si tratta di Internet o di una sottorete NAT rimarrà comunque una domanda.
7h3rAm

@ 7h3rAm, è un buon punto, il DCHP non richiede una connessione a Internet, errore mio.

Ciò richiede solo una connessione NIC di rete a cui è stato assegnato un indirizzo IP. A differenza di tutte le altre risposte, non richiede una connessione a LAN, router, firewall, ISP fino a un altro sistema. Non riesce ancora a dimostrare che la scheda NIC è connessa se si tratta di un indirizzo non DHCP assegnato (statico)
user150471

@utente150471, già sottolineato, grazie per il tuo contributo.

3

Ecco la mia versione

import requests

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

1
Mi piace questo, ma sarebbe meglio se si escludesse un timeout specifico o un errore di connessione generato dalle richieste. Così com'è, un Ctrl-C fulmineo verrà stampato offline.
user2561747

2

Una moderna soluzione portatile con 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

Oppure, una versione che solleva un'eccezione:

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

Il modo migliore per farlo è quello di controllarlo con un indirizzo IP che python fornisce sempre se non riesce a trovare il sito web. In questo caso questo è il mio codice:

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

il mio preferito, quando eseguo script su un cluster o no

import subprocess

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

questo funziona wget tranquillamente, non scaricando nulla ma controllando che il file remoto dato esista sul web


0

Prendendo la risposta di Unutbu come punto di partenza e dopo essere stato masterizzato in passato da un indirizzo IP "statico" che cambia, ho creato una semplice classe che controlla una volta usando una ricerca DNS (cioè usando l'URL " https: // www .google.com "), quindi memorizza l'indirizzo IP del server di risposta per utilizzarlo nei controlli successivi. In questo modo, l'indirizzo IP è sempre aggiornato (supponendo che la classe venga reinizializzata almeno una volta ogni pochi anni). Do anche credito a gawry per questa risposta , che mi ha mostrato come ottenere l'indirizzo IP del server (dopo ogni reindirizzamento, ecc.). Si prega di ignorare l'apparente hackiness di questa soluzione, vado per un esempio minimo di lavoro qui. :)

Ecco cosa ho:

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

Prendendo la risposta di Six, penso che potremmo semplificare in qualche modo, un problema importante poiché i nuovi arrivati ​​si perdono in questioni altamente tecniche.

Ecco cosa finalmente userò per aspettare che la mia connessione (3G, lenta) venga stabilita una volta al giorno per il mio monitoraggio fotovoltaico.

Funziona con Pyth3 con 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)       

durata massima: 5 minuti se raggiunto proverò tra un'ora ma è un altro po 'di script!


il tuo essai var non si abitua, vero?
kidCoder

0

Prendendo la risposta di Ivelin e aggiungere un po 'di controllo in più come il mio router fornisce il suo indirizzo IP 192.168.0.1 e restituisce una testa se non ha connessione a Internet quando interrogazione 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

Questo funziona per me in 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

Ne ho aggiunti alcuni al codice di 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

Per i miei progetti utilizzo lo script modificato per eseguire il ping del server DNS pubblico di Google 8.8.8.8. Utilizzo di un timeout di 1 secondo e librerie core di Python senza dipendenze esterne:

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

Il valore di timeout selezionato è 1, ma in questo esempio può essere un numero a virgola mobile di scelta che fallisce più rapidamente di 1 secondo.


0

richieste di importazione e prova questo semplice codice Python.

def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
    _ = requests.get(url, timeout=timeout)
    return True
except requests.ConnectionError:
return False
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.