Python异步反向DNS查找

3 投票
3 回答
3639 浏览
提问于 2025-04-18 08:57

我想在短时间内对大量的反向DNS进行查询。目前我已经用socket.gethostbyaddr和concurrent.futures线程池实现了异步查询,但性能还是不理想。比如说,这个脚本在处理2500个IP地址时花了大约22分钟。

我在想有没有更快的方法来完成这个任务,而不需要使用像adns-python这样的工具。我找到了一篇文章,里面提供了一些额外的背景知识,地址是http://blog.schmichael.com/2007/09/18/a-lesson-on-python-dns-and-threads/

代码片段:

ips = [...]
with concurrent.futures.ThreadPoolExecutor(max_workers = 16) as pool:
    list(pool.map(get_hostname_from_ip, ips))
def get_hostname_from_ip(ip):
    try:
        return socket.gethostbyaddr(ip)[0]
    except:
        return ""

我觉得问题的一部分在于,很多IP地址无法解析,导致超时。我尝试过:

socket.setdefaulttimeout(2.0)

但似乎没有什么效果。

3 个回答

0

请使用异步DNS,其他的选择会让你的性能很差。

1

因为有一个叫做 全局解释器锁 的东西,所以你应该使用 ProcessPoolExecutor 来处理任务。这里有更多信息

3

我发现我主要的问题是IP地址无法解析,因此套接字没有遵循设定的超时时间,结果在30秒后失败。可以参考这个链接:Python 2.6 urlib2 超时问题

adns-python不太适合,因为它不支持IPv6(没有补丁的话)。

经过一番搜索,我找到了这个:使用dnspython进行反向DNS查找,并在我的代码中实现了类似的版本(他的代码还使用了可选的线程池,并实现了超时功能)。

最后,我使用了dnspython和一个concurrent.futures线程池来进行异步的反向DNS查找(可以查看这个链接:Python:共享主机中的反向DNS查找Dnspython:设置查询超时/生命周期)。通过设置1秒的超时,这样在处理2500个IP地址时,运行时间从大约22分钟缩短到了大约16秒。这么大的差异可能与套接字上的全局解释器锁和30秒的超时有关。

代码片段:

import concurrent.futures
from dns import resolver, reversename
dns_resolver = resolver.Resolver()
dns_resolver.timeout = 1
dns_resolver.lifetime = 1
ips = [...]
results = []

with concurrent.futures.ThreadPoolExecutor(max_workers = 16) as pool:
    results = list(pool.map(get_hostname_from_ip, ips))

def get_hostname_from_ip(ip):
    try:
        reverse_name = reversename.from_address(ip)
        return dns_resolver.query(reverse_name, "PTR")[0].to_text()[:-1]
    except:
        return ""

撰写回答