2013-07-02 3 views
1

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

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

Я нашел эту дискуссию How to find running time of a thread in Python, которая, по-видимому, подразумевает, что это не тривиально. Есть идеи? Благодарю.

Edit:

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

#! /usr/bin/python 

import socket 

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
s.settimeout(0.5) 

try: 
     s.connect(('192.168.2.5',22)) 
except Exception, e: 
     print 'connection failed' 

s.close() 

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

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

#! /usr/bin/python 

import socket 
import fcntl 
import struct 

def check_connection(): 

     ifaces = ['eth0','wlan0'] 
     connected = [] 

     i = 0 
     for ifname in ifaces: 

      s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
      try: 
       socket.inet_ntoa(fcntl.ioctl(
         s.fileno(), 
         0x8915, # SIOCGIFADDR 
         struct.pack('256s', ifname[:15]) 
       )[20:24]) 
       connected.append(ifname) 
       print "%s is connected" % ifname 
      except: 
       print "%s is not connected" % ifname 

      i += 1 

     return connected 

connected_ifaces = check_connection() 

if len(connected_ifaces) == 0: 
    print 'not connected to any network' 
else: 
    print 'connected to a network using the following interface(s):' 
    for x in connected_ifaces: 
     print '\t%s' % x 

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.settimeout(0.5) 

    try: 
      s.connect(('192.168.2.5',22)) 
      print 'connected to hostname' 
    except Exception, e: 
      print 'connection to hostname failed' 

    s.close() 
+0

http://stackoverflow.com/questions/3764291/checking-network-connection – NPE

+0

@NPE благодарит за идею. Мне нравится параметр тайм-аута в urllib2.urlopen, но мне кажется, вам нужно, чтобы на этом хосте работал веб-сервер, чтобы это работать, чего у меня нет. – nomadicME

+0

В тех случаях, когда доступ к сети возможен, но DNS-сервер отсутствует, вы хотите пройти или провалиться? Если ответ «pass» или «do not care», вы можете поместить тайм-аут на «connect» на IP-адрес гораздо проще, чем на поиск DNS. Если ответ «сбой» (и вы не заботитесь о том, чтобы различать случаи), вам нужно сделать что-то сложное, как вы предлагаете. – abarnert

ответ

2

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

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

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

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

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

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

Простейшая вещь, вероятно, join с таймаутом ... за исключением того, что вы закончите тем, что фоновый поток работает после таймаута, и если вы попытаетесь выйти до его завершения, Python может (и будет, с CPython 2.7 или 3.3 на большинство основных платформ) ждут, пока это закончится, прежде чем уйти. Путь к исправлению заключается в использовании потока daemon, но тогда вы не можете юридически join его. Вы можете демонизировать его после таймаута, но я думаю, что здесь Event проще.

Так, например:

event = threading.Event() 

def blocking_dns(): 
    socket.gethostbyname(host) 
    event.set() 

thread = threading.Thread(target=blocking_dns) 
thread.daemon = True 
thread.start() 
success = event.wait(timeout) 

Вот общего назначения обертка:

def run_with_timeout(timeout, func, *args, **kwargs): 
    event = threading.Event() 
    def wrapper(): 
     func(*args, **kwargs) 
     event.set() 
    thread = threading.Thread(target=wrapper, args=args, kwargs=kwargs) 
    thread.daemon = True 
    thread.start() 
    return event.wait(timeout) 

Что вы можете использовать так:

dns_works = run_with_timeout(5.0, socket.gethostbyname, 'www.google.com') 

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

+0

Благодарим вас за подробный ответ. Как я уже сказал в моем редактировании оригинального вопроса, простое соединение сокета с таймаутом сделало трюк. Тем не менее, я очень рад, что вы решили ответить на часть вопроса, потому что я действительно хотел знать, как это сделать. – nomadicME

1

, если вы находитесь на системе окон вы можете использовать это

x = os.system("ping -n 1 google.com") 
if x == 0: 
    print "HOST IS CONNECTED :) " 
+0

Почему вы считаете, что запуск программы, которая вызывает 'gethostbyname', будет лучше, чем просто называть ее? Зачем использовать 'system', когда документы для него говорят, что вы почти никогда не будете использовать его? Зачем делать что-то конкретное для Windows, когда это на самом деле сложнее, чем делать кросс-платформу? – abarnert

+0

Да os.system не следует использовать часто, но в этом случае вы можете. Во-первых, PING - это кросс-платформенная команда, но * NIX и Windows могут обрабатывать os.system без каких-либо проблем. – blackwind

+0

Windows 'ping' не имеет такого же синтаксиса, как POSIX ping ... но, что более важно, ваш ответ конкретно говорит« если вы находитесь в системе Windows », что сильно означает, что это ответ на Windows. – abarnert

Смежные вопросы