我正在尝试编写一个发送多个DNS请求的python脚本,为每个请求使用不同的名称服务器。
使用dnspython实现顺序解决方案很容易,但对我来说太慢了。 使用线程池添加并发是不可能的,因为在我的特定情况下,所有请求都使用相同的源端口(REUSE_ADDRESS在这里也没有帮助)。
由于上述原因,我正在考虑使用以下解决方案(放弃使用dnspython的解析器模块,但利用其消息构建和解析模块):
我的主要问题是:
答案 0 :(得分:0)
您是否尝试过aiodns
套餐? https://pypi.python.org/pypi/aiodns/
对于超时,asyncio具有标准wait_for
协程(https://docs.python.org/3/library/asyncio-task.html#asyncio.wait_for)。
答案 1 :(得分:0)
使用简单的选择循环在此处运行良好。以下是完成的代码段:
def run(self, resolvers_iter):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, 0)
sock.setblocking(False)
try:
pending = []
# For rate limiting
limit = float(self.timeout)/self.max_pending # delay between sends
last_sent = clock() - limit
# Work as long as there are more resolvers to query
completed_sending = False
while not completed_sending or pending:
# Can I send more requests
want_to_write = False
if not completed_sending and len(pending) < self.max_pending:
want_to_write = True
# Calculate nearest timeout time to make sure select returns on time
timeout = None
if pending:
timeout = self.timeout - clock() + pending[0][0] + 0.001
timeout = max(timeout, 0)
# Rate limit
time_passed_since_send = clock() - last_sent
if want_to_write and time_passed_since_send + 0.001 < limit:
timeout = min(timeout, limit-time_passed_since_send)
timeout = max(timeout, 0)
want_to_write = False
# Poll socket - uses internally the select module
readable, writable = self._select(readable=True, writable=want_to_write, timeout=timeout)
# Can read
if readable:
# Read as many as possible
while True:
try:
# Get response
response, from_address = DnsFacilities.read_response(sock)
# Check if not duplicate or already timed out
sent_time = None
for i, (t, ip) in enumerate(pending):
if ip == from_address[0]:
sent_time = t
del pending[i]
break
if sent_time is not None:
self.response_received((response, from_address, clock()-sent_time))
except socket.error, e:
if e[0] in (socket.errno.EWOULDBLOCK, socket.errno.EAGAIN):
break
elif e[0] in (socket.errno.WSAECONNRESET, socket.errno.WSAENETRESET):
pass
else:
raise
# Can write
if writable:
try:
last_sent = clock()
resolver_address = resolvers_iter.next()
DnsFacilities.send_query(resolver_address)
pending.append((clock(), resolver_address)
except StopIteration:
completed_sending = True
# Check for timed out tasks
now = clock()
while pending and now - pending[0][0] > self.timeout:
self.response_timeout(pending[0][1])
del pending[0]
finally:
sock.close()