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

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

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

Ответ 1

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

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

Ответ 2

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

  • Избегайте разрешения 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 socket.error as ex:
    print(ex)
    return False

internet()

Другим подходом может быть отправка вручную созданного 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

Ответ 3

Быстрее будет просто делать запрос 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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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)

Ответ 8

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

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

Ответ 9

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

Ответ 10

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

import requests

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

Ответ 11

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

import subprocess

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

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

Ответ 12

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

Ответ 13

Взяв unutbu answer в качестве отправной точки, и, будучи сгоревшим в прошлом с помощью "статического" изменения 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()

Ответ 14

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

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

Ответ 15

Принимая ответ 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 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

Ответ 16

Это работает для меня в 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")