Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用asyncio和dnspython异步发送DNS查询_Python_Dns_Coroutine_Python Asyncio_Dnspython - Fatal编程技术网

使用asyncio和dnspython异步发送DNS查询

使用asyncio和dnspython异步发送DNS查询,python,dns,coroutine,python-asyncio,dnspython,Python,Dns,Coroutine,Python Asyncio,Dnspython,假设我想使用dnspython为Alexa top 1M站点发送各种类型的DNS查询(A、AAAA、NS、SOA、DNSKEY、NSEC3、DS等) 一个接一个地这样做会花费一些时间,因为我要为每个站点发送多个查询。因此,我希望在Python3中使用asyncio执行一些并行性 我看了大卫的发电机/协同程序三部曲,但我仍然不知道如何完成我的简单任务 更具体地说 results = dns.resolver.query('google.com','AAAA') 是一个阻塞函数调用,等待DNS回复

假设我想使用dnspython为Alexa top 1M站点发送各种类型的DNS查询(A、AAAA、NS、SOA、DNSKEY、NSEC3、DS等)

一个接一个地这样做会花费一些时间,因为我要为每个站点发送多个查询。因此,我希望在Python3中使用asyncio执行一些并行性

我看了大卫的发电机/协同程序三部曲,但我仍然不知道如何完成我的简单任务

更具体地说

results = dns.resolver.query('google.com','AAAA')
是一个阻塞函数调用,等待DNS回复返回

在等待期间,我如何在不使用线程的情况下发送其他查询?由于DNS查询通常是udp数据包,我认为asyncio可能会有所帮助

pycares似乎不支持我需要的所有记录类型,因此pycares和aiodns不适用于我的案例


任何参考资料和想法都会有帮助

最近,DNSPython现在已经有了本机异步IO支持,不过

尽管如此,现在可以使用dnspython进行查询,而不需要黑客线程池解决方案

AsyncIO DNSPython示例 下面是一个使用包装函数使用dnspython的AsyncIO
Resolver
类和
AsyncIO.gather
高效进行批量查询的简单示例:

从dns.asyncresolver导入解析程序
导入dns.resolver
导入dns.rrset
导入异步
从输入导入元组开始
异步定义dns_查询(域:str,rtype:str='A',**kwargs)->dns.rrset.rrset:
kwargs,res_cfg=dict(kwargs),{}
#从kwargs中提取“filename”和“configure”(如果存在)
#要传递给解析程序。我们将其弹出以避免通过kwargs时发生冲突
#to.resolve()。
如果kwargs:res_cfg['filename']=kwargs.pop('filename')中的'filename'
如果kwargs:res_cfg['configure']=kwargs.pop('configure')中的'configure'
#创建一个异步IO解析器实例
rs=解析器(**res\u cfg)
#调用并异步等待.resolve()以获取DNS结果
res:dns.resolver.Answer=wait rs.resolve(域,rdtype=rtype,**kwargs)
#我们返回答案中最有用的部分:RRset,它包含
#找到的个人记录。
返回res.rrset
异步定义dns_批量(*查询:元组[str,str],**kwargs):
ret_ex=kwargs.pop('return_exceptions',True)
#迭代查询并调用(但不要等待)dns_查询协同路由
#每一个查询。
#如果没有“等待”,它们将无法正常执行,直到我们等待协同程序
#可以单独使用,也可以使用asyncio.gather批量使用
coros=[dns_查询(dom,rt,**kwargs)用于dom,rt-in-list(查询)]
#使用asyncio.gather,我们可以有效地运行所有的协同路由
#而不是一个接一个地等待他们。
#
#return\u异常控制是否立即
#失败并在检测到异常时立即重新引发,
#或者它是否应该捕获任何异常,并且
#在结果中返回它们。
#
#在此示例函数中,return_exceptions设置为True,
#这意味着如果一个或多个查询失败,它将
#存储异常并继续运行剩余的CORO,
#并返回结果元组/列表中的异常。
return wait asyncio.gather(*coros,return\u exceptions=ret\u ex)
异步def main():
查询=[
('privex.io','AAAA'),
('privex.io','TXT'),
('google.com','A'),
('google.com','AAAA'),
('examplesitedoesnotexist.test','A'),
]
打印(f“\n[…]发送{len(查询)}批量查询\n”)
res=等待dns_批量(*查询)
打印(f“\n[++]获得{len(res)}结果!:)\n\n”)
对于i,枚举中的a(res):
打印(“\n---------------------------------------------------------------\n”)
如果存在(a,异常):
打印(f“[!!!]错误:结果{i}是异常!原始查询:{querys[i]}| |异常是:{type(a)}-{a!s}\n”)
持续
打印(f“[++]获取查询{i}({querys[i]})的结果)\n”)
打印(f“>>>表示:{a!r}”)
打印(f“>>>为字符串:”)
打印(f“{a!s}”)
打印()
打印(“\n---------------------------------------------------------------\n”)
asyncio.run(main())
以下是运行上述脚本时的输出:


 [...] Sending 5 bulk queries


 [+++] Got 5 results! :)



------------------------------------------------------------

 [+++] Got result for query 0 ( ('privex.io', 'AAAA') )

  >>>  Representation: <DNS privex.io. IN AAAA RRset: [<2a07:e00::abc>]>
  >>>  As string:
    privex.io. 221 IN AAAA 2a07:e00::abc


------------------------------------------------------------

 [+++] Got result for query 1 ( ('privex.io', 'TXT') )

  >>>  Representation: <DNS privex.io. IN TXT RRset: [<"v=spf1 include:spf.messagingengine.com include:smtp.privex.io -all">, <"google-site-verification=_0OlLdacq3GAc4NkhOd0pBcLsNya3KApS0iAc6MtbYU">]>
  >>>  As string:
    privex.io. 300 IN TXT "v=spf1 include:spf.messagingengine.com include:smtp.privex.io -all"
privex.io. 300 IN TXT "google-site-verification=_0OlLdacq3GAc4NkhOd0pBcLsNya3KApS0iAc6MtbYU"


------------------------------------------------------------

 [+++] Got result for query 2 ( ('google.com', 'A') )

  >>>  Representation: <DNS google.com. IN A RRset: [<216.58.205.46>]>
  >>>  As string:
    google.com. 143 IN A 216.58.205.46


------------------------------------------------------------

 [+++] Got result for query 3 ( ('google.com', 'AAAA') )

  >>>  Representation: <DNS google.com. IN AAAA RRset: [<2a00:1450:4009:80f::200e>]>
  >>>  As string:
    google.com. 221 IN AAAA 2a00:1450:4009:80f::200e


------------------------------------------------------------

 [!!!] Error: Result 4 is an exception! Original query: ('examplesitedoesnotexist.test', 'A') || Exception is: <class 'dns.resolver.NXDOMAIN'> - The DNS query name does not exist: examplesitedoesnotexist.test. 


------------------------------------------------------------
如果您为AsyncIO后台任务运行上述示例代码,则输出将如下所示,表明
lorem
hello
都可以与主入口点函数并排运行:

 [...] waiting 5 secs
hello world
lorem ipsum dolor
lorem ipsum dolor
hello world
lorem ipsum dolor
lorem ipsum dolor
hello world
lorem ipsum dolor
 [...] stopping tsk_hello
 [...] waiting 4 secs
lorem ipsum dolor
lorem ipsum dolor
lorem ipsum dolor
lorem ipsum dolor
 [...] stopping tsk_lorem

不幸的是,如果
aiodns
pycares
不能满足您的需要,您应该使用同步
dnspython
库。您可以通过
res=yield from loop.run\u in\u executor()
在线程池中执行它。出于好奇:pycares不支持哪些DNS记录?您熟悉asyncio吗?David的生成器和协同程序幻灯片非常好,但很多工作都是在asyncio中完成的,在asyncio中,您基本上使用事件循环并使用“yield from”运行阻塞代码。因此,其他代码可以同时运行。@AndrewSvetlov正如我在问题帖中提到的,我需要执行一些与DNSSEC相关的查询,比如DNSKEY、DS。pycares不支持它们。@shongolo使用线程池和事件循环之间有什么关系?它们是同一个想法吗?@Eniaczz与asyncio您可以使用线程池,如果您想通过在执行器()中运行,但您不需要使用它们。对于您的情况,相关的概念似乎是,各种“屈服于”点为asyncio提供了在等待阻塞代码运行时在各种协同路由/任务之间来回切换的机会。
 [...] waiting 5 secs
hello world
lorem ipsum dolor
lorem ipsum dolor
hello world
lorem ipsum dolor
lorem ipsum dolor
hello world
lorem ipsum dolor
 [...] stopping tsk_hello
 [...] waiting 4 secs
lorem ipsum dolor
lorem ipsum dolor
lorem ipsum dolor
lorem ipsum dolor
 [...] stopping tsk_lorem