Проверка сетевого подключения - PullRequest
109 голосов
/ 22 сентября 2010

Я хочу посмотреть, смогу ли я получить доступ к онлайн-API, но для этого мне нужен доступ в Интернет.

Как узнать, доступно ли соединение с использованием Python и активно ли оно?

Ответы [ 15 ]

117 голосов
/ 22 сентября 2010

Возможно, вы могли бы использовать что-то вроде этого:

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), заключается в том, что для полного доменного имени требуется поиск DNS. Когда на машине нет работающего подключения к Интернету, сам поиск DNS может заблокировать вызов на urllib_request.urlopen более чем на секунду. Спасибо @rzetterberg за указание на это.


Если указанный выше фиксированный IP-адрес не работает, вы можете найти текущий IP-адрес для google.com (в Unix), введя

% dig google.com  +trace 
...
google.com.     300 IN  A   216.58.192.142
84 голосов
/ 14 октября 2015

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

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

Чтобы соответствовать этим требованиям, можно использовать один из следующих способов: проверить, является ли один из Googleобщедоступные DNS-серверы достижимы.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

Как мы видим, TCP / 53 открыт и нефильтруют.Если вы не являетесь пользователем root, не забывайте использовать аргумент 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 по TCP / 53.Теперь мы можем установить соединение сокетов на 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.message
...     return False
...
>>> internet()
True
>>>

Другой подход может состоять в том, чтобы отправить вручную созданный DNS-зонд на один из этих серверов и ждатьответ.Но, я полагаю, это может оказаться медленнее по сравнению из-за отбрасывания пакетов, сбоя разрешения DNS и т. Д. Пожалуйста, прокомментируйте, если считаете иначе.

ОБНОВЛЕНИЕ № 1: Благодаря комментарию @ theamk, время ожидания теперь является аргументоми по умолчанию инициализируется 3 с.

ОБНОВЛЕНИЕ № 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
51 голосов
/ 24 апреля 2015

Будет быстрее сделать запрос 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
18 голосов
/ 28 июня 2014

В качестве альтернативы ответам Убутну / Кевина С я использую пакет 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
16 голосов
/ 05 ноября 2011

Просто чтобы обновить сказанное 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.

9 голосов
/ 22 сентября 2010

Вы можете просто попытаться загрузить данные, и если соединение не будет установлено, вы узнаете, что с подключением что-то не так.

В основном вы не можете проверить, подключен ли компьютер к Интернету.Причин может быть много, например, неправильная конфигурация DNS, брандмауэры, NAT.Поэтому, даже если вы проведете несколько тестов, вы не сможете гарантировать, что у вас будет соединение с API, пока вы не попробуете.

6 голосов
/ 04 сентября 2015
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)

3 голосов
/ 22 сентября 2010

Попробуйте операцию, которую вы пытались выполнить в любом случае.Если это не удается, Python должен выдать вам исключение, чтобы сообщить вам.

Для того, чтобы сначала выполнить какую-то тривиальную операцию, чтобы обнаружить соединение, будет введено состояние гонки.Что, если подключение к Интернету действительно, когда вы тестируете, но отключается, прежде чем вам нужно будет выполнить реальную работу?

2 голосов
/ 09 февраля 2016

Это может не работать, если localhost был изменен с 127.0.0.1 Попробуйте

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-адресом локального хоста. Надеюсь, это поможет

1 голос
/ 28 мая 2019

Вот моя версия

import requests

try:
    if requests.get('https://google.com').ok:
        print("You're Online")
except:
    print("You're Offline")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...