Перевірка підключення до мережі


133

Я хочу дізнатися, чи можу я отримати доступ до інтернет-API, але для цього мені потрібно мати доступ до Інтернету.

Як я можу побачити, чи є підключення доступне та активне за допомогою Python?


якщо ви знаходитесь у python, це майже напевно викине виняток у разі збою в зв’язку чи тайм-ауту. Ви можете або спробувати / наздогнати це, або просто випустити його на поверхню.
jdizzle

1
@Triptych: Я сподіваюся, що це був жарт, тому що це не працює
inspectorG4dget

1
@ inspectorG4dget:easy_install system_of_tubes
S.Lott

2
@aF: Подивіться на рішення Unutbu. Він показує (найшвидшим способом), як перевірити, чи можете ви отримати доступ до google.com. Якщо ваша проблема стосується доступу до API, то чому б не спробувати отримати доступ до неї, встановивши тайм-аут = 1? Це точно скаже вам, чи доступний API, до якого ви хочете отримати доступ. Як тільки ви це знаєте, ви можете продовжити та отримати доступ до API або почекати час, коли зможете отримати доступ до нього.
inspectorG4dget

Як я вже сказав, мені просто потрібна була така проста річ, як сказала унутбу. Не потрібно з цим метушитися ..
aF.

Відповіді:


132

Можливо, ви могли б використовувати щось подібне:

import urllib2

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

Наразі 216.58.192.142 - одна з IP-адрес для google.com. Змініть http://216.58.192.142на будь-який сайт, можна очікувати, що він швидко відповість .

Цей фіксований IP не буде відображатись на google.com назавжди. Тож цей код не є надійним - для його роботи буде потрібно постійне обслуговування.

Причина, чому вищевказаний код використовує фіксовану IP-адресу замість повністю кваліфікованого доменного імені (FQDN), полягає в тому, що для FQDN потрібен пошук DNS. Якщо апарат не має робочого з’єднання з Інтернетом, сам пошук DNS може блокувати виклик urllib_request.urlopenбільше секунди. Дякуємо @rzetterberg за вказівку на це.


Якщо виправлена ​​IP-адреса вище не працює, ви можете знайти поточну IP-адресу для google.com (на unix), запустивши

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

1
Просто зауваження про те, що "дзвінок urlopenне займе набагато більше 1 секунди, навіть якщо Інтернет не" включений "." - цитата. Це неправда, якщо наданий URL недійсний, пошук DNS блокується. Це справедливо лише для фактичного підключення до веб-сервера. Найпростіший спосіб уникнути цього блоку пошуку DNS - використовувати замість цього IP-адресу, тоді гарантовано зайняти лише 1 секунду :)
rzetterberg

8
ЦЕ НЕ БІЛЬШЕ РОБОТИ. Станом на вересень 2013 року , через тривалий час вимкнулося 74.125.113.99 , тому ця функція завжди поверне помилкову. Я думаю, Google змінив налаштовану мережу.
theamk

4
Тепер решта просте. Google для "74.125.113.99 urllib". Він поверне тисячі проектів з відкритим кодом, які включили невірний код. (для мене якраз перша сторінка містить щонайменше 5: nvpy, sweekychebot, malteDict, upy, checkConnection). Вони зараз усі зламані.
theamk

4
Якщо це не зрозуміло, я НЕ РЕКОМЕНДУЮ за цим методом. Старий ІР був хороший менше 3 років. Новий ІР працює сьогодні. Помістіть це у свій проект, і він може таємничо зламатись менше ніж за 3 роки.
theamk

1
Е ... просто відкрийте, http://google.comі тоді ви вирішите всі проблеми, про які тут все говорять. Не потрібно використовувати ip-адресу ...
Jason C

106

Якщо ми можемо підключитися до якогось інтернет-сервера, то ми справді маємо зв’язок. Однак для найшвидшого та надійного підходу всі рішення повинні відповідати принаймні таким вимогам:

  • Уникайте роздільної здатності DNS (нам знадобиться IP, відомий і гарантований, що він буде доступний більшу частину часу)
  • Уникайте з'єднань рівня додатків (підключення до послуги HTTP / FTP / IMAP)
  • Уникайте дзвінків на зовнішні утиліти з Python або іншої мови на вибір (нам потрібно придумати мовно-агностичне рішення, яке не покладається на сторонні рішення)

Для дотримання цих завдань може бути один підхід - перевірити, чи доступний один із загальнодоступних серверів DNS Google . Адресами IPv4 для цих серверів є 8.8.8.8і 8.8.4.4. Ми можемо спробувати підключитися до будь-якого з них.

Швидкий Nmap хоста 8.8.8.8дав нижче результат:

$ 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

Як ми бачимо, 53/tcpвін відкритий і не фільтрується. Якщо ви некористувач, не забудьте скористатися sudoабо -Pnаргументом для Nmap для надсилання створених пакетів зондів і визначте, чи хост працює.

Перш ніж ми спробуємо з Python, давайте перевіримо підключення за допомогою зовнішнього інструменту Netcat:

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

Netcat підтверджує, що ми можемо досягти 8.8.8.8переваги 53/tcp. Тепер ми можемо встановити з'єднання з сокетом 8.8.8.8:53/tcpв Python, щоб перевірити з'єднання:

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

Іншим підходом може бути надіслати розроблений вручну DNS-зонд на один із цих серверів і чекати відповіді. Але, я припускаю, це може виявитися повільніше порівняно із падінням пакетів, збоєм роздільної здатності DNS тощо. Будь ласка, коментуйте, якщо ви думаєте про інше.

ОНОВЛЕННЯ №1: Завдяки коментарю @ @ theamk, тайм-аут тепер є аргументом та ініціалізовано до 3sтипового.

ОНОВЛЕННЯ №2: Я зробив швидкі тести, щоб визначити найшвидший і загальний варіант реалізації всіх дійсних відповідей на це питання. Ось підсумок:

$ 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

І ще раз:

$ 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у наведеному вище висновку означає, що всі ці реалізації від відповідних авторів правильно ідентифікують підключення до Інтернету. Час відображається з роздільною здатністю мілісекунд.

ОНОВЛЕННЯ №3: Тестується знову після зміни обробки виключень:

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
Це найкраща відповідь, уникаючи дозволу DNS, і як не дивно, консультаційна служба DNS Google на порт 53.
m3nda

1
@AviMehenwal Google надає цю IP-адресу як частину свого безкоштовного користування службою вирішення імен DNS. IP не повинен змінюватися, якщо Google не вирішить інше. Я використовую його як альтернативний сервер DNS вже кілька років без жодних проблем.
7h3rAm

1
@Luke Дякую, що вказали на це. Я оновив відповідь, щоб повідомити користувачів про виняток і повернути False як відповідь за замовчуванням.
7h3rAm

2
@JasonC Підключення до TCP / 53 відрізняється від з'єднання DNS через порт 53. За вашою аналогією кожен порт TCP, який використовується додатком, буде класифікований як протокол підключення до рівня програми. Ні, це неправда. Підключення через TCP-розетку до порту НЕ підключається на рівні програми. Я не роблю пошук DNS, а просто половину рукостискання TCP. Це не те саме, що робити повний пошук DNS.
7h3rAm

2
Чи не варто закликати close()до розетки?
брк

60

Швидше буде просто зробити HEAD-запит, щоб не отримати жодного HTML-коду.
Крім того, я впевнений, що Google хотів би це краще таким чином :)

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
Займає всього 20 мілісекунд, тоді як верхня відповідь займає 1 секунду.
Уоллі

8
+1 Немає сенсу завантажувати всю сторінку, якщо ви хочете лише перевірити, чи сервер доступний та відповідає. Завантажте вміст, якщо вам потрібен контент
той

Без будь-якої причини використання URL-адреси "8.8" все ще працює, що, очевидно, "8.8" або " 8.8 " не працює в реальному веб-браузері.
Полв

2 години шукаю робочого рішення, а потім я знайшов це ... чистим і простим
Педро Серпа

21

Як альтернатива відповідям на ubutnu / Kevin C я використовую такий requestsпакет:

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

Бонус: цю функцію можна поширити на цю функцію, яка надсилає веб-сайт.

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
Запит - це чудова бібліотека. Однак, на відміну від багатьох прикладів тут, я б використав IANA's example.com або example.org як більш надійний довгостроковий вибір, оскільки це повністю контролюється ICANN .
хіраль

Чи є інший спосіб перевірити стан роботи в Інтернеті. Тому що якщо ви google.comзнову пінгінете , вони заблокують наш IP. Так чи є інший спосіб.?
Санджив

15

Просто для оновлення того, що сказав unutbu для нового коду в Python 3.2

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

І, лише зауважте, тут вхід (посилання) - це URL-адреса, яку ви хочете перевірити: я пропоную вибрати те, що швидко з'єднується там, де ви живете, - тобто я живу в Південній Кореї, тому я, певно, встановив посилання на http: / /www.naver.com .


Я зачекаю 30 секунд, якщо немає сервера DNS.
Віктор

10

Ви можете просто спробувати завантажити дані, і якщо з'єднання не вдасться, ви знатимете, що щось із з'єднанням не в порядку.

В основному ви не можете перевірити, чи комп'ютер підключений до Інтернету. Причин збою може бути багато, наприклад, неправильна конфігурація DNS, брандмауері, NAT. Тож навіть якщо ви зробите кілька тестів, ви не можете гарантувати, що будете мати зв’язок зі своїм API, поки ви не спробуєте.


2
"Простіше просити пробачення, ніж дозволу"
кабал

це не повинно бути таким хорошим. Мені просто потрібно спробувати підключитися до сайту або щось пінг, і якщо це дає тайм-аут voilá. Як я можу це зробити?
aF.

Чи є якась причина, що ви не можете просто спробувати підключитися до API? Чому ви повинні перевірити це перед реальним з’єднанням?
Томаш Вісоцький

Я роблю сторінку html за допомогою python. Сторінка html описується на аргументах, які я даю в програмі python. Мені потрібно лише ввести HTML-код, якщо я можу отримати доступ до api. Ось чому я повинен знати раніше.
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!' )

Для python 3 використовуйте urllib.request.urlopen(host)


4

Спробуйте операцію, яку ви намагалися зробити в будь-якому випадку. Якщо це не вдасться, python повинен надати вам виняток, щоб повідомити про це.

Спершу спробувати якусь тривіальну операцію для виявлення зв'язку, буде введення умови перегону. Що робити, якщо підключення до Інтернету є дійсним під час тестування, але виходить з ладу, перш ніж потрібно виконати фактичну роботу?


3

Це може не спрацювати, якщо localhost було змінено на 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 )

Якщо не редагувати, IP-адреса ваших комп’ютерів буде 127.0.0.1, коли він не підключений до Інтернету. Цей код отримує IP-адресу, а потім запитує, чи це IP-адреса localhost. Сподіваюся, що це допомагає


Це цікава перевірка, хоча вона виявить лише, якщо ви підключені до мережі. Незалежно від того, чи це Інтернет, чи NAT-підмережа, залишатиметься питанням.
7h3rAm

@ 7h3rAm, це хороший момент, DCHP не вимагає підключення до Інтернету, моя помилка.

Це просто вимагає мережевого підключення NIC, якому отримано призначений IP. На відміну від усіх інших відповідей, він не потребує підключення до локальної мережі, маршрутизатора, брандмауера, ISP аж до іншої системи. Він все ще не показує, що NIC підключений, якщо це не призначена DHCP адреса (статична)
user150471

@ user150471, вже вказано, дякую за ваш внесок.

3

Ось моя версія

import requests

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

1
Мені це подобається, але було б краще, якби воно виключало певну помилку очікування або з'єднання, що виникає із запитів. Як і, блискавичний Ctrl-C надрукує офлайн.
користувач2561747

2

Сучасне портативне рішення з 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

Або версія, яка викликає виняток:

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

Найкращий спосіб це зробити, щоб він перевірив IP-адресу, яку завжди дає python, якщо він не може знайти веб-сайт. У цьому випадку це мій код:

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

мій улюблений, коли сценарії виконуються на кластері чи ні

import subprocess

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

це запускається wget тихо, не завантажуючи нічого, окрім перевірки наявності даного віддаленого файлу в Інтернеті


0

Приймаючи відповідь унутбу як вихідну точку і в минулому спалювавшись "статичною" зміною IP-адреси, я створив простий клас, який перевіряє один раз за допомогою пошуку DNS (тобто, використовуючи URL-адресу " https: // www .google.com "), а потім зберігає IP-адресу відповідного сервера для використання під час наступних перевірок. Таким чином, IP-адреса завжди актуальна (якщо припустимо, що клас повторно ініціалізується щонайменше раз на кілька років або близько того). Я також даю подяку Gawry за цю відповідь , яка показала мені, як отримати IP-адресу сервера (після будь-якого перенаправлення тощо). Будь ласка, ігноруйте очевидну нерозумність цього рішення, я тут навожу мінімальний робочий приклад. :)

Ось що я маю:

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

Відповідаючи на шести відповідей, я думаю, що ми могли б якось спростити, важливе питання, оскільки новачки втрачаються у високо технічних питаннях.

Ось, що я, нарешті, використаю, щоб чекати, коли моє з'єднання (3G, повільний) буде встановлено один раз на день для мого PV-моніторингу.

Працює під Pyth3 з 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)       

Максимальна тривалість: 5 хвилин, якщо досягнуто, я спробую за одну годину, але це ще один біт сценарію!


ваш essai var не звикає, чи не так?
kidCoder

0

Отримуючи відповідь Ivelin і додайте додаткову перевірку, оскільки мій маршрутизатор доставляє свою ip адресу 192.168.0.1 і повертає голову, якщо у неї немає підключення до Інтернету при запиті на 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

Це працює для мене в 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

Я додав декілька до коду Джоела.

    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

Для своїх проектів я використовую скрипт, модифікований для пінг-сервера відкритого DNS google 8.8.8.8. Використання тайм-ауту в 1 секунду та основні бібліотеки python без зовнішніх залежностей:

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

Значення тайм-ауту вибору становить 1, але може бути числом з плаваючою комою вибору, щоб вийти з ладу швидше, ніж 1 секунда в цьому прикладі.


0

імпортуйте запити та спробуйте цей простий код python.

def check_internet():
url = 'http://www.google.com/'
timeout = 5
try:
    _ = requests.get(url, timeout=timeout)
    return True
except requests.ConnectionError:
return False
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.