Python套接字.settimeout()在连接到关闭的域时不起作用



我需要检查主机是快速启动还是关闭。为此,我在建立连接之前添加了一个套接字超时,但套接字超时似乎不起作用。为什么?

这是我的代码:

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)

我大约需要10-20秒,而不是指定的超时(1秒(。

之所以会发生这种情况,是因为Python套接字的超时不会限制用于DNS查找的时间。由于您使用的域名需要解析为IP,因此s.connect((hostname, port))首先需要对hostname进行DNS查询,然后才能使用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()

最新更新