Проверка соединения сокета python

Обновлено: 19.05.2024

Я нашел вариант, обсуждаемый здесь, который отлично работает, если хост подключен к сети. Однако socket.gethostbyname(hostname) долгое время зависает, если хост не подключен.

Я видел предложение запустить socket.gethostbyname(hostname) в потоке, и если этот поток не возвратил результат за указанный период, предположим, что он не подключен. Я подумал, что это хорошая идея, но я недостаточно разбираюсь в потоках (хотя я использовал их успешно), чтобы знать, как это сделать.

Я нашел это обсуждение Как найти время выполнения потока в Python, который, по-видимому, подразумевает, что это не тривиально. Есть идеи? Благодарю.

Редактировать:

Я должен признать свое невежество. Я не понял (хотя должен был), что socket.gethostbyname(hostname) выполняет поиск DNS. Итак, я собрал это просто, чтобы проверить подключение сокета к интересующему узлу на порту 22:

Примечание. Это не будет проверять существующее соединение с сетью и будет зависать, если оно не подключено.

Сначала этот скрипт проверяет подключение к сети, если соединение обнаружено, то он проверяет наличие определенного хоста в этой сети:

Там хороший шанс, что блокирующий вызов gethostbyname самом деле не нужен здесь.

Во-первых, вы можете вообще не искать DNS-поиск, и почти все, что вы можете делать с сокетами, например, connect -already обрабатывает таймауты.

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

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

Итак, как вы это делаете?

Ну, вы можете join к потоку с таймаутом. Или вы можете подождать Condition или Event которые может подавать фоновый поток, или, при select , на pipe , к которой может писать фоновый поток.

Здесь универсальная оболочка:

Что вы можете использовать следующим образом:

Использование Event для чего-то менее тривиального, чем это становится сложным (и часто вы не можете видеть, что это сложно, и писать код, который работает 99% времени, и невозможно отладить другие 1%). Обычная проблема заключается в том, что вы можете пропустить set из фонового потока. Если вы не заботитесь ли set происходит, прежде чем вы даже проверили, или только после того, как вы стали ждать, вы можете использовать Event ; в противном случае вам нужно Condition .

Для создания сокета существует функция, называемая socket . Она принимает аргументы family , type и proto (подробнее см. в документации). Чтобы создать TCP-сокет, нужно использовать socket.AF_INET или socket.AF_INET6 для family и socket.SOCK_STREAM для type .

Пример Python socket:

Функция возвращает объект сокета, который имеет следующие основные методы:

  • bind()
  • listen()
  • accept()
  • connect()
  • send()
  • recv()

Здесь мы создаем серверный сокет, привязываем его к localhost и 50000-му порту и начинаем прослушивать входящие соединения.

Чтобы принять входящее соединение, мы вызываем метод accept() , который будет блокироваться до тех пор, пока не подключится новый клиент. Когда это произойдет, метод создаcт новый сокет и вернет его вместе с адресом клиента.

Затем он в бесконечном цикле считывает данные из сокета партиями по 1024 байта, используя метод recv() , пока не вернет пустую строку. После этого он отправляет все входящие данные обратно, используя метод sendall() , который в свою очередь многократно вызывает метод send() . И после этого сервер просто закрывает клиентское соединение. Данный пример может обрабатывать только одно входящее соединение, потому что он не вызывает accept() в цикле.

Код на стороне клиента выглядит проще:

Вместо методов bind() и listen() он вызывает только метод connect() и сразу же отправляет данные на сервер. Затем он получает обратно 1024 байта, закрывает сокет и выводит полученные данные.

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

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

Существует множество интерфейсов для разных операционных систем:

Все они примерно одинаковы, поэтому давайте создадим сервер с помощью Python select. Пример Python select :

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

Создание серверного сокета происходит так же, кроме одной строки: server.setblocking(0) . Это нужно для того, чтобы сокет не блокировался. Такой сервер более продвинутый, поскольку он может обслуживать более одного клиента. Главная причина заключается в сокетах selecting :

Этот вызов (если не передан аргумент timeout ) блокирует программу до тех пор, пока какие-либо из переданных сокетов не будут готовы. В этот момент вызов вернет три списка сокетов для указанных операций.

Так работают сокеты на низком уровне. Однако в большинстве случаев нет необходимости реализовывать настолько низкоуровневую логику. Рекомендуется использовать более высокоуровневые абстракции, такие как Twisted, Tornado или ZeroMQ, в зависимости от ситуации.

Я все еще смущен тем, что знаю статус моего подключения к соке. Это то, что я делаю.

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

По большому счету, я обнаружил, что client.recv() вернет пустую строку или client.recv() выкинет исключение (но не было исключения, когда я остановил свой сервер). Но что, если сам сервер иногда посылает пустую строку? Если я попытаюсь восстановить соединение, проверив пустую строку, он выдает исключение, которое уже связано. Объяснение здесь (как сказать, было ли соединение мертвым в python) не работает для меня.

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

спросил(а) 2016-03-08T10:29:00+03:00 5 лет, 8 месяцев назад

s_closed result pic s_closed возвращает true/false, поскольку wie lin сказал, его там (я использовал и протестировал его, можно увидеть на картинке). или вы можете использовать s.___ getstate__

ответил(а) 2017-01-17T21:25:00+03:00 4 года, 10 месяцев назад

socket.fileno() Возвращает дескриптор файла сокетов (небольшое целое число) или -1 при сбое. Это полезно при выборе select.select().

Также сокет является технически списком, с помощью которого вы можете найти тег [закрытый]

ответил(а) 2017-07-22T09:00:00+03:00 4 года, 4 месяца назад

Следующее - это то, что я использую, но я очень новичок в этом, поэтому, пожалуйста, предоставьте отзыв, если есть лучший или более эффективный способ сделать это, и я обновлю этот ответ.

Кажется, что лучший способ сделать это - проверить getpeername() (тестирование socket.recv() здесь плохо, так как наш тест, например, изменил бы буфер).

Верните адрес удаленной конечной точки. Для IP-сокетов информация о адресе - это пара (hostaddr, порт).

Если это не удается, он вызывает socket.error [Errno 9] Bad file descriptor.

Примечание. У меня есть первая проверка if, потому что я тестирую атрибут, который также может быть None.

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

Кроме того, в другом ответе упоминается, что fileno() возвращает отрицательное число, если локальная сторона сокета закрыта. Я получаю ту же ошибку 9. В любом случае это не проверяет другую сторону в случае, если это действительно.

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

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

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

Причина, по которой в приведенном выше коде используется фиксированный IP-адрес вместо полного доменного имени (FQDN), заключается в том, что для полного доменного имени требуется поиск DNS. Если на компьютере нет работающего подключения к Интернету, сам поиск DNS может заблокировать вызов urllib_request.urlopen более чем на секунду. Спасибо @rzetterberg за то, что указал на это.

Современное портативное решение с requests :

Или версия, которая вызывает исключение:

Принимая ответ unutbu в качестве отправной точки и будучи сожженным в прошлом в результате «статического» изменения IP-адреса, я Мы создали простой класс, который проверяет один раз, используя поиск в DNS (то есть, используя URL "https://www.google.com. "), а затем сохраняет IP-адрес отвечающего сервера для использования при последующих проверках. Таким образом, IP-адрес всегда актуален (при условии, что класс повторно инициализируется не реже одного раза в несколько лет). Я также благодарен Гаври за этот ответ, который показал мне, как получить IP-адрес сервера (после любого перенаправления и т. Д. . ) . Пожалуйста, не обращайте внимания на очевидное хакерство этого решения, я приведу здесь минимальный рабочий пример. :)

Вот что у меня есть:

Для Python 3 используйте urllib.request.urlopen(host)

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

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

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

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

Я добавил несколько к коду Джоэла.

Просто чтобы обновить сказанное unutbu для нового кода в Python 3.2

Будет быстрее сделать запрос HEAD, поэтому HTML не будет загружен.
Кроме того, я уверен, что Google хотел бы это лучше :)

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

Если не отредактировано, IP вашего компьютера будет 127.0.0.1, если он не подключен к Интернету. Этот код в основном получает IP-адрес, а затем спрашивает, является ли он IP-адресом локального хоста. надеюсь, это поможет

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

Чтобы соответствовать им, одним из подходов может быть проверка того, является ли один из общедоступным DNS Google серверы достижимы. Адреса IPv4 для этих серверов: 8.8.8.8 и 8.8.4.4 . Мы можем попробовать подключиться к любому из них.

Быстрый Nmap хоста 8.8.8.8 дал следующий результат:

Как мы видим, TCP / 53 открыт и не фильтруется. Если вы не являетесь пользователем root, не забудьте использовать аргумент sudo или -Pn для Nmap для отправки специально созданных тестовых пакетов и определения, работает ли хост.

Прежде чем мы попробуем использовать Python, давайте проверим подключение с помощью внешнего инструмента Netcat:

Netcat подтверждает, что мы можем связаться с 8.8.8.8 через TCP / 53. Теперь мы можем установить сокетное соединение на 8.8.8.8:53/TCP в Python для проверки соединения:

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

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

True в вышеприведенном выводе означает, что все эти реализации соответствующих авторов правильно идентифицируют подключение к Интернету. Время показывается с разрешением в миллисекундах.

ОБНОВЛЕНИЕ № 3: Проверено снова после изменения обработки исключений:

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

Вот что я, наконец, буду использовать, чтобы дождаться, пока мое соединение (3G, медленное) будет устанавливаться один раз в день для моего PV мониторинга.

Работает под Pyth3 с Raspbian 3.4.2

Максимальный пробег: 5 минут, если достигнут, я попробую через час, но это еще один сценарий!

Сегодня мы рассмотрим пример программирования сокетов Python. Мы создадим серверные и клиентские приложения на Python.

Программирование сокетов

Чтобы понять программирование сокетов Python, нам нужно знать о трех интересных темах – Socket Server, Socket Client и Socket.

Итак, что такое сервер? Сервер – это программное обеспечение, которое ожидает запросов клиентов и обслуживает или обрабатывает их соответственно.

С другой стороны, клиент запрашивает эту услугу. Клиентская программа запрашивает некоторые ресурсы к серверу, и сервер отвечает на этот запрос.

Socket – это конечная точка двунаправленного канала связи между сервером и клиентом. Сокеты могут обмениваться данными внутри процесса, между процессами на одной машине или между процессами на разных машинах. Для любого взаимодействия с удаленной программой мы должны подключаться через порт сокета.

Основная цель этого руководства по программированию сокетов – познакомить вас с тем, как сервер сокетов и клиент взаимодействуют друг с другом. Вы также узнаете, как написать программу сервера сокетов в Python.

Пример

Ранее мы говорили, что клиент сокета запрашивает некоторые ресурсы у сервера, и сервер отвечает на этот запрос.

Итак, мы разработаем и серверную, и клиентскую модель, чтобы каждый мог общаться с ними. Шаги можно рассматривать так:

Сервер сокетов

Мы сохраним программу сервера сокетов, как socket_server.py. Чтобы использовать соединение, нам нужно импортировать модуль сокета.

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

Мы можем получить адрес хоста с помощью функции socket.gethostname(). Рекомендуется использовать адрес порта пользователя выше 1024, поскольку номер порта меньше 1024 зарезервирован для стандартного интернет-протокола.

Смотрите приведенный ниже пример кода сервера:

Итак, наш сервер сокетов работает на порту 5000 и будет ждать запроса клиента. Если вы хотите, чтобы сервер не завершал работу при закрытии клиентского соединения, просто удалите условие if и оператор break. Цикл while используется для бесконечного запуска серверной программы и ожидания клиентского запроса.

Клиент сокета

Мы сохраним клиентскую программу сокета python как socket_client.py. Эта программа похожа на серверную, за исключением привязки.

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

Смотрите ниже пример кода клиента сокета:

Вывод

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

Наконец, напишите «до свидания» из клиентской программы, чтобы завершить обе программы. Ниже короткое видео покажет, как это работало на моем тестовом прогоне примеров программ сервера сокетов и клиента.

python socket programming, python socket server

Обратите внимание, что сервер сокетов работает на порту 5000, но клиенту также требуется порт сокета для подключения к серверу. Этот порт назначается случайным образом при вызове клиентского соединения. В данном случае это 57822.

Читайте также: