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

134

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

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

аР.
источник
Если вы находитесь в Python, он почти наверняка выдаст исключение в случае сбоя соединения или тайм-аута. Вы можете либо попытаться обойти это, либо просто позволить этому всплыть.
Jdizzle
1
@Triptych: Я надеюсь , что это была шутка, потому что она не работает
inspectorG4dget
1
@ inspectorG4dget:easy_install system_of_tubes
С.Лотт
2
@aF: Посмотрите на решение Unutbu. Он показывает (самым быстрым из возможных способов), как проверить, есть ли у вас доступ к google.com. Если ваша проблема касается доступа к API, то почему бы не попробовать получить к нему доступ, установив timeout = 1? Это точно скажет вам, доступен ли API, к которому вы хотите получить доступ. Как только вы это узнаете, вы можете получить доступ к API или подождать, пока вы сможете получить к нему доступ.
инспектор
Как я уже сказал, мне просто нужна была простая вещь, как сказал unutbu. Вам не нужно суетиться с этим ..
А.Ф.

Ответы:

133

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

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
unutbu
источник
1
Просто отметка о том, что «звонок urlopenне займет больше 1 секунды, даже если Интернет не включен» - цитата. Это неверно, если предоставленный URL-адрес недействителен, поиск DNS будет заблокирован. Это верно только для реального подключения к веб-серверу. Самый простой способ избежать этого блока поиска DNS - использовать вместо него IP-адрес, тогда это гарантированно займет всего 1 секунду :)
rzetterberg
8
ЭТО БОЛЬШЕ НЕ РАБОТАЕТ. По состоянию на сентябрь 2013 года значение 74.125.113.99 истекает по прошествии длительного времени, поэтому эта функция всегда будет возвращать значение False. Я полагаю, Google изменил их сеть настроена.
theamk
4
Теперь все остальное просто. Google для "74.125.113.99 urllib". Он вернет тысячи проектов с открытым исходным кодом, которые содержат неправильный код. (для меня только первая страница содержит как минимум 5: nvpy, sweekychebot, malteseDict, upy, checkConnection). Они все сейчас сломаны.
theamk
4
Если неясно, я НЕ РЕКОМЕНДУЮ использовать этот метод. Старый IP прослужил меньше 3 лет. Новый IP работает сегодня. Поместите его в свой проект, и он снова может загадочным образом сломаться менее чем через 3 года.
theamk
1
Э-э ... просто открой, http://google.comи тогда ты решишь все проблемы, о которых все здесь говорят. Нет необходимости использовать IP-адрес ...
Джейсон Си,
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открыт и не фильтруется. Если вы не являетесь пользователем 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руку помощи 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, 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
7h3rAm
источник
6
Это лучший ответ, позволяющий избежать разрешения DNS и, по иронии судьбы,
обратиться к
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()розетку?
brk
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 » не работает в реальном веб-браузере.
Polv
2 часа искал рабочее решение, а потом я нашел это ... чистым и простым
Педро Серпа
21

В качестве альтернативы ответам Убутну / Кевина С я использую такой 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
Def_Os
источник
1
Request - отличная библиотека. Однако, в отличие от многих примеров здесь, я бы использовал example.com или example.org IANA как более надежный долгосрочный выбор, поскольку он полностью контролируется ICANN .
chirale
Есть ли другой способ проверить работоспособность интернета. Потому что, если вы 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
«Проще просить прощения, чем разрешения»
cobbal
это не должно быть так хорошо. Мне просто нужно попытаться подключиться к сайту или пинговать что-то, и если это дает тайм-аут, вуаля. Как я могу это сделать?
А.Ф.
Есть ли причина, по которой вы не можете просто попытаться подключиться к API? Почему вы должны проверять это перед настоящим подключением?
Tomasz Wysocki
Я делаю html-страницу на Python. HTML-страница зависит от аргументов, которые я привожу в программе Python. Мне нужно только добавить HTML-код, если я могу получить доступ к API. Вот почему мне нужно знать раньше.
А.Ф.
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 должен выдать вам исключение, чтобы вы знали.

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

mluebke
источник
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. В отличие от всех других ответов, он не требует подключения к локальной сети, маршрутизатору, брандмауэру, интернет-провайдеру вплоть до другой системы. Он по-прежнему не может показать, что сетевая
карта
@ user150471, уже отмечалось, спасибо за ваш вклад.
3

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

import requests

try:
    if requests.get('https://google.com').ok:
        print("You're Online")
except:
    print("You're Offline")
Муджиб Исак
источник
1
Мне нравится этот, но было бы лучше, если бы он исключал конкретный тайм-аут или ошибку соединения, возникающую из запросов. Как и, молниеносно Ctrl-C будет печатать в автономном режиме.
user2561747 06
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("")
lunar_kitsune
источник
1

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

import subprocess

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

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

neok
источник
0

Взяв ответ 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()
Джаред Б.
источник
0

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

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

Seylione
источник
твой essai var не используется, не так ли?
kidCoder
0

Принимая ответ Ивелина и добавьте дополнительную проверку, поскольку мой маршрутизатор выдает свой 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 секунда в этом примере.

Luv
источник
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
Раушан Кумар
источник