Sprawdzam połączenie sieciowe


133

Chcę sprawdzić, czy mogę uzyskać dostęp do internetowego interfejsu API, ale do tego potrzebuję dostępu do Internetu.

Jak mogę sprawdzić, czy jest dostępne i aktywne połączenie przy użyciu Pythona?


jeśli jesteś w Pythonie, prawie na pewno zgłosi wyjątek w przypadku awarii połączenia lub przekroczenia limitu czasu. Możesz spróbować / złapać się wokół tego lub po prostu wypuścić to na powierzchnię.
jdizzle

1
@Triptych: Mam nadzieję, że to był żart, bo to nie działa
inspectorG4dget

1
@ inspectorG4dget:easy_install system_of_tubes
S.Lott

2
@aF: Spójrz na rozwiązanie Unutbu. Pokazuje (w najszybszy możliwy sposób), jak sprawdzić, czy masz dostęp do google.com. Jeśli twój problem dotyczy dostępu do API, to dlaczego nie spróbować uzyskać do niego dostępu, ustawiając timeout = 1? Dzięki temu dowiesz się dokładnie, czy API, do którego chcesz uzyskać dostęp, jest dostępne. Kiedy już to wiesz, możesz przejść dalej i uzyskać dostęp do interfejsu API lub poczekać, aż uzyskasz do niego dostęp.
inspectorG4dget

Tak jak powiedziałem, potrzebowałem tylko prostej rzeczy, takiej jak powiedział unutbu. Nie musisz robić z tym takiego zamieszania…
aF.

Odpowiedzi:


132

Być może przydałoby się coś takiego:

import urllib2

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

Obecnie 216.58.192.142 to jeden z adresów IP w witrynie google.com. Zmień http://216.58.192.142witrynę, w której można oczekiwać szybkiej reakcji .

Ten stały adres IP nie będzie na zawsze mapowany na google.com. Więc ten kod nie jest solidny - będzie wymagał ciągłej konserwacji, aby działał.

Powodem, dla którego powyższy kod używa stałego adresu IP zamiast w pełni kwalifikowanej nazwy domeny (FQDN), jest to, że nazwa FQDN wymagałaby wyszukiwania DNS. Gdy komputer nie ma działającego połączenia internetowego, samo wyszukiwanie DNS może blokować wywołanie urllib_request.urlopenna dłużej niż sekundę. Dzięki @rzetterberg za wskazanie tego.


Jeśli powyższy stały adres IP nie działa, możesz znaleźć aktualny adres IP dla google.com (w systemie unix), uruchamiając

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

1
Tylko uwaga na temat „Połączenie z urlopennumerem nie zajmie dużo więcej niż 1 sekundę, nawet jeśli Internet nie jest włączony”. - cytat. Nie jest to prawdą, jeśli podany adres URL jest nieprawidłowy, wyszukiwanie DNS zostanie zablokowane. Dotyczy to tylko rzeczywistego połączenia z serwerem WWW. Najprostszym sposobem uniknięcia tego bloku wyszukiwania DNS jest użycie zamiast tego adresu IP, wtedy gwarantowane zajmie tylko 1 sekundę :)
rzetterberg

8
TO JUŻ NIE DZIAŁA. Od września 2013 r. 74.125.113.99 przekroczył limit czasu po długim czasie, więc ta funkcja zawsze zwraca wartość False. Przypuszczam, że Google zmienił konfigurację swojej sieci.
theamk

4
Teraz reszta jest prosta. Google dla „74.125.113.99 urllib”. Zwróci tysiące projektów open source, które zawierały nieprawidłowy kod. (dla mnie tylko pierwsza strona zawiera co najmniej 5: nvpy, sweekychebot, malteseDict, upy, checkConnection). Wszystkie są teraz zepsute.
theamk

4
Jeśli nie jest to jasne, NIE POLECAM stosowania tej metody. Stare IP było dobre przez mniej niż 3 lata. Nowy adres IP działa dzisiaj. Umieść to w swoim projekcie, a za mniej niż 3 lata znowu może się zepsuć.
theamk

1
Eee ... po prostu otwórz, http://google.coma potem rozwiąż wszystkie problemy, o których wszyscy tu mówią. Nie ma potrzeby używania adresu IP ...
Jason C

106

Jeśli możemy połączyć się z jakimś serwerem internetowym, to rzeczywiście mamy łączność. Jednak aby uzyskać najszybsze i najbardziej niezawodne podejście, wszystkie rozwiązania powinny spełniać co najmniej następujące wymagania:

  • Unikaj rozpoznawania nazw DNS (będziemy potrzebować adresu IP, który jest dobrze znany i na pewno będzie dostępny przez większość czasu)
  • Unikaj połączeń w warstwie aplikacji (łączenie się z usługą HTTP / FTP / IMAP)
  • Unikaj wywołań zewnętrznych narzędzi z Pythona lub innego wybranego języka (musimy wymyślić rozwiązanie niezależne od języka, które nie polega na rozwiązaniach innych firm)

Aby spełnić te wymagania, jednym z podejść może być sprawdzenie, czy jeden z publicznych serwerów DNS Google jest osiągalny. Adresy IPv4 tych serwerów to 8.8.8.8i 8.8.4.4. Możemy spróbować połączyć się z dowolnym z nich.

Szybki Nmap hosta 8.8.8.8dał następujący wynik:

$ 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

Jak widać, 53/tcpjest otwarty i niefiltrowany. Jeśli jesteś użytkownikiem niż root, należy pamiętać, aby używać sudolub -Pnargumentem dla Nmap wysłać spreparowane pakiety sondy i ustalić, czy komputer jest w górę.

Zanim spróbujemy z Pythonem, przetestujmy łączność za pomocą zewnętrznego narzędzia, Netcat:

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

Netcat potwierdza, że możemy osiągnąć 8.8.8.8w ciągu 53/tcp. Teraz możemy skonfigurować połączenie przez gniazdo 8.8.8.8:53/tcpw Pythonie, aby sprawdzić połączenie:

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

Innym podejściem może być wysłanie ręcznie spreparowanej sondy DNS na jeden z tych serwerów i oczekiwanie na odpowiedź. Zakładam jednak, że może się to okazać wolniejsze w porównaniu z powodu zrzucania pakietów, błędu rozpoznawania nazw DNS itp. Jeśli myślisz inaczej, skomentuj.

UPDATE # 1: Dzięki komentarzowi @ theamk, timeout jest teraz argumentem i 3sjest domyślnie inicjowany .

AKTUALIZACJA # 2: Zrobiłem szybkie testy, aby zidentyfikować najszybszą i najbardziej ogólną implementację wszystkich prawidłowych odpowiedzi na to pytanie. Oto podsumowanie:

$ 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

I jeszcze raz:

$ 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

Truew powyższym wyniku oznacza, że ​​wszystkie te implementacje od poszczególnych autorów poprawnie identyfikują łączność z Internetem. Czas jest wyświetlany z rozdzielczością milisekund.

AKTUALIZACJA # 3: Przetestowano ponownie po zmianie obsługi wyjątków:

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
To najlepsza odpowiedź, unikając rozwiązywania DNS i, jak na ironię, konsultując się z usługą DNS Google na porcie 53.
m3nda

1
@AviMehenwal Google udostępnia ten adres IP w ramach bezpłatnej usługi rozpoznawania nazw DNS. Adres IP nie powinien się zmieniać, chyba że Google zdecyduje inaczej. Od kilku lat używam go jako alternatywnego serwera DNS bez żadnych problemów.
7h3rAm

1
@Luke Dzięki za zwrócenie uwagi. Zaktualizowałem odpowiedź, aby poinformować użytkowników o wyjątku i zwrócić False jako domyślną odpowiedź.
7h3rAm

2
@JasonC Łączenie się z TCP / 53 różni się od połączenia DNS przez port 53. Postępując analogicznie, każdy port TCP używany przez aplikację będzie klasyfikowany jako połączenie protokołu na poziomie aplikacji. Nie, to nie prawda. Łączenie się przez gniazdo TCP z portem NIE JEST połączeniem na poziomie aplikacji. Nie robię wyszukiwania DNS, a raczej uzgadnianie pół TCP. To nie to samo, co pełne wyszukiwanie DNS.
7h3rAm

2
Nie powinniśmy zadzwonić close()do gniazdka?
brk

60

Szybciej będzie po prostu wykonać żądanie HEAD, więc żaden kod HTML nie zostanie pobrany.
Jestem też pewien, że Google polubiłoby to lepiej :)

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
Zajmuje tylko 20 miliardów sekund, podczas gdy najlepsza odpowiedź zajmuje 1 sekundę.
Wally,

8
+1 Nie ma sensu pobierać całej strony, jeśli chcesz tylko sprawdzić, czy serwer jest osiągalny i odpowiada. Pobierz zawartość, jeśli potrzebujesz zawartości
jestIch

Bez powodu używanie adresu URL „8.8” nadal działa, co oczywiście „8.8” lub „ 8.8 ” nie działa w prawdziwej przeglądarce internetowej.
Polv

2 godziny szukania działającego rozwiązania, a potem znalazłem to ... czyste i proste
Pedro Serpa

21

Jako alternatywę dla odpowiedzi ubutnu / Kevina C używam tego requestspakietu:

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: można to rozszerzyć na tę funkcję, która pinguje stronę internetową.

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
Żądanie to świetna biblioteka. Jednak w przeciwieństwie do wielu przykładów tutaj, użyłbym IANA example.com lub example.org jako bardziej niezawodnego długoterminowego wyboru, ponieważ jest w pełni kontrolowany przez ICANN .
chirale

Czy istnieje inny sposób sprawdzenia stanu działania Internetu? Ponieważ jeśli google.comznowu będziesz tęsknić , zablokują nasze IP. Więc czy jest jakiś inny sposób.?
Sanjiv

15

Wystarczy zaktualizować to, co powiedział unutbu dla nowego kodu w Pythonie 3.2

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

I, dla przypomnienia, dane wejściowe tutaj (odniesienie) to adres URL, który chcesz sprawdzić: Proponuję wybrać coś, co łączy się szybko w miejscu Twojego zamieszkania - tj. Mieszkam w Korei Południowej, więc prawdopodobnie ustawiłbym odniesienie na http: / /www.naver.com .


Poczekam 30 sekund, jeśli nie ma dostępnego serwera DNS.
Viktor Joras

10

Możesz po prostu spróbować pobrać dane, a jeśli połączenie się nie powiedzie, będziesz wiedział, że coś z połączeniem nie jest w porządku.

Zasadniczo nie możesz sprawdzić, czy komputer jest podłączony do Internetu. Przyczyn niepowodzenia może być wiele, np. Zła konfiguracja DNS, zapory sieciowe, NAT. Więc nawet jeśli wykonasz kilka testów, nie możesz zagwarantować, że będziesz mieć połączenie z interfejsem API, dopóki nie spróbujesz.


2
„Łatwiej jest prosić o przebaczenie niż o pozwolenie”
cobbal

to nie musi być aż tak dobre. Po prostu muszę spróbować połączyć się ze stroną lub pingować coś, a jeśli to da limit czasu voilá. Jak mogę to zrobić?
aF.

Czy jest jakiś powód, dla którego nie możesz po prostu spróbować połączyć się z API? Dlaczego musisz to sprawdzić przed prawdziwym połączeniem?
Tomasz Wysocki

Tworzę stronę html za pomocą Pythona. Strona html zależy od argumentów, które podam w programie w Pythonie. Muszę tylko umieścić kod HTML, jeśli mam dostęp do interfejsu API. Dlatego muszę wiedzieć wcześniej.
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!' )

W przypadku Pythona 3 użyj urllib.request.urlopen(host)


4

Spróbuj wykonać operację, którą mimo wszystko próbujesz wykonać. Jeśli to się nie powiedzie, Python powinien zgłosić wyjątek, aby Cię powiadomić.

Aby najpierw wypróbować jakąś trywialną operację w celu wykrycia połączenia, należy wprowadzić stan wyścigu. Co się stanie, jeśli połączenie internetowe jest prawidłowe podczas testu, ale znika, zanim będziesz musiał wykonać rzeczywistą pracę?


3

To może nie działać, jeśli localhost został zmieniony z 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 )

O ile nie jest edytowany, adres IP twojego komputera będzie 127.0.0.1, gdy nie jest podłączony do Internetu. Ten kod w zasadzie pobiera adres IP, a następnie pyta, czy jest to adres IP lokalnego hosta. Mam nadzieję, że to pomoże


To interesująca kontrola, ale zidentyfikuje tylko wtedy, gdy masz połączenie z siecią. Pozostaje pytanie, czy jest to Internet, czy podsieć NAT.
7h3rAm

@ 7h3rAm, to dobra uwaga, DCHP nie wymaga połączenia z Internetem, mój błąd.

Wymaga to tylko połączenia sieciowego NIC, któremu został przypisany adres IP. W przeciwieństwie do wszystkich innych odpowiedzi, nie wymaga połączenia z siecią LAN, routerem, zaporą ogniową, usługodawcą internetowym aż do innego systemu. Nadal nie pokazuje, że karta sieciowa jest podłączona, jeśli jest adresem przypisanym innym niż DHCP (statyczny)
user150471

@ user150471, już wskazałem, dziękuję za wkład.

3

Oto moja wersja

import requests

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

1
Podoba mi się ten, ale byłoby lepiej, gdyby wyłączał określony limit czasu lub błąd połączenia, który jest zgłaszany przez żądania. Tak jak jest, błyskawiczne Ctrl-C wydrukuje w trybie offline.
user2561747

2

Nowoczesne przenośne rozwiązanie z 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

Lub wersja, która zgłasza wyjątek:

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

Najlepszym sposobem na to jest sprawdzenie adresu IP, który Python zawsze podaje, jeśli nie może znaleźć witryny. W tym przypadku jest to mój kod:

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

mój ulubiony, gdy uruchamiam skrypty w klastrze lub nie

import subprocess

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

to uruchamia wget cicho, niczego nie pobiera, tylko sprawdza, czy dany plik zdalny istnieje w sieci


0

Biorąc odpowiedź unutbu za punkt wyjścia i będąc w przeszłości spalonym przez „statyczną” zmianę adresu IP, stworzyłem prostą klasę, która sprawdza raz za pomocą wyszukiwania DNS (tj. Używając adresu URL „ https: // www .google.com ”), a następnie przechowuje adres IP serwera odpowiadającego do wykorzystania podczas kolejnych kontroli. W ten sposób adres IP jest zawsze aktualny (zakładając, że klasa jest ponownie inicjowana co najmniej raz na kilka lat). Daję również uznanie Gawry'emu za tę odpowiedź , która pokazała mi, jak uzyskać adres IP serwera (po każdym przekierowaniu itp.). Proszę zignorować pozorną hacking tego rozwiązania, posłużę się tutaj minimalnym działającym przykładem. :)

Oto co mam:

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

Biorąc odpowiedź Six, myślę, że moglibyśmy w jakiś sposób uprościć, ważna kwestia, ponieważ nowicjusze gubią się w wysoce technicznych sprawach.

Tutaj w końcu będę czekał, aż moje połączenie (3G, wolne) zostanie ustanowione raz dziennie do monitorowania PV.

Działa pod Pyth3 z 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)       

maksymalny bieg: 5 minut jeśli osiągnę spróbuję za godzinę, ale to kolejny kawałek skryptu!


twój essai var się nie przyzwyczaja, prawda?
kidCoder

0

Biorąc odpowiedź Ivelina i dodając dodatkowe sprawdzenie, ponieważ mój router dostarcza swój adres IP 192.168.0.1 i zwraca głowę, jeśli nie ma połączenia z Internetem podczas wysyłania zapytania do 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

To działa dla mnie w Pythonie 3.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

Dodałem kilka do kodu Joela.

    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

W moich projektach używam zmodyfikowanego skryptu do pingowania publicznego serwera DNS Google 8.8.8.8. Korzystanie z limitu czasu wynoszącego 1 sekundy i podstawowych bibliotek Pythona bez zewnętrznych zależności:

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

Wybierz wartość limitu czasu wynosi 1, ale może być liczbę zmiennoprzecinkową wyboru niepowodzenie łatwiej niż 1 sekundę w tym przykładzie.


0

importuj żądania i wypróbuj ten prosty kod w Pythonie.

def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
    _ = requests.get(url, timeout=timeout)
    return True
except requests.ConnectionError:
return False
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.