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