我需要快速检查主机是否启动或关闭。为此,我在建立连接之前添加了套接字超时,但套接字超时似乎不起作用。为什么?
这是我的代码:
import socket
def test_hostname(hostname, port):
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.settimeout(1.0) # timeout
try:
s.connect((hostname, port))
except (socket.timeout, socket.gaierror):
return False
else:
return True
finally:
s.close()
result = test_hostname("001.com",80) # 001.com is down
print(result)
Run Code Online (Sandbox Code Playgroud)
我花了大约 10-20 秒而不是指定的超时(1 秒)。
发生这种情况是因为 Python 套接字的超时不限制DNS 查找所花费的时间。由于您使用的域名需要解析为 IP,因此您s.connect((hostname, port))首先需要对 进行 DNS 查询hostname,然后才能使用 DNS 服务器返回的 IP 之一创建连接(如果任何)。
该域001.com似乎未解析为任何 IP 地址,因此您的系统可能需要几秒钟的时间才能返回故障。发生这种情况时,Python 将退出并且连接将失败,但超时时间早已过期。
如果您知道要访问的主机的 IP 地址,请使用该地址而不是主机名。如果没有,您将必须使用 DNS 解析库来超时 DNS 解析,例如dnspython:
import socket
import dns.resolver
def test_hostname(hostname, port):
resolver = dns.resolver.Resolver()
resolver.timeout = resolver.lifetime = 1
try:
answer = resolver.resolve(hostname, 'A')
except dns.exception.Timeout:
return False
if not answer.rrset:
return False
addr = next(iter(answer.rrset)).to_text()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(1)
try:
s.connect((addr, port))
except (socket.timeout, socket.gaierror):
return False
else:
return True
finally:
s.close()
Run Code Online (Sandbox Code Playgroud)