我找到了一个讨论here的选项,如果主机连接到网络,该选项很有效。但是,如果主机未连接,socket.gethostbyname(hostname)
会挂起很长时间。
我看到了在线程中运行socket.gethostbyname(hostname)
的建议,如果此线程未在指定的时间段内返回结果,则假设它未连接。我认为这是一个好主意,但我对线程(虽然我已经成功使用它)知道如何做到这一点还不够熟练。
我发现这个讨论How to find running time of a thread in Python似乎意味着这不是微不足道的。有任何想法吗?感谢。
修改
我必须承认自己的无知。我没有意识到(虽然我应该)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 :(得分:2)
这里实际上不需要对gethostbyname
进行阻止调用。
首先,你可能根本不想进行DNS查找,而且几乎所有你可以用套接字做的事情 - 例如,connect
- 已经处理了超时。
其次,如果您确实需要在DNS查找上超时,则可能需要使用像pycares这样的异步DNS库。
但是如果你需要在DNS查找上超时,并且你不能依赖外部代码,那么你是对的,你将不得不在另一个线程中运行DNS查找,并在主线程中等待它。 / p>
那么,你是怎么做到的?
好吧,你可以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
。
答案 1 :(得分:1)
如果你在Windows系统上 你可以用这个
x = os.system("ping -n 1 google.com")
if x == 0:
print "HOST IS CONNECTED :) "