Проверка сетевого подключения



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



Как я могу увидеть, если есть соединение доступно и активно с помощью Python?

741   13  

13 ответов:

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

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


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

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

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

  • избегайте разрешения 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

как мы видим, 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 Exception as ex:
...     print ex.message
...     return False
...
>>> internet()
True
>>>

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

UPDATE #1: благодаря комментарию @theamk, timeout теперь является аргументом и инициализируется до 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

это будет быстрее, чтобы просто сделать запрос головы, так что никакой 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

просто чтобы обновить то, что 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.

в качестве альтернативы ответам 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

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

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

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)

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

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

лучший способ сделать это-проверить его на 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("")

С unutbu это в качестве отправной точки, и были сожжены в прошлом году такой "статический" 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()

Это может не сработать, если 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-адрес localhost . Надеюсь, что это поможет

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

вот что я, наконец, буду использовать, чтобы дождаться моего соединения (3G, slow), которое будет установлено один раз в день для моего мониторинга 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 минут, если достигнуто, я попробую через один час, но это еще один бит скрипта!

мой любимый, при запуске скриптов на кластере или нет

import subprocess

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

это работает wget тихо, не загружая ничего, но проверяя, что данный удаленный файл существует в интернете

Comments

    Ничего не найдено.