1

リクエストごとに異なるネームサーバーを使用して、複数の DNS リクエストを送信する python スクリプトを作成しようとしています。

シーケンシャル ソリューションの実装は dnspython を使用すると簡単ですが、私には遅すぎます。私の特定のケースでは、すべてのリクエストが同じソースポートを使用するため、スレッドプールを使用して同時実行を追加することはできません(REUSE_ADDRESSはここでも役に立ちません)。

上記の理由から、次の解決策を使用することを考えています (dnspython のリゾルバー モジュールの使用を捨てますが、メッセージ構築および解析モジュールを利用します)。

  • 最大 X 個のリクエストの進行を許可する
  • Xリクエストを同時に送信します(udpを使用してdnsリクエストパケットを送信するだけです。おそらくバーストを避けるために送信間に遅延を追加します)
  • 別のスレッドが応答を待ちます
  • 応答が到着したら、それを要求と (アドレスで) 照合し、新しい要求の実行を許可します
  • 要求への応答が TIMEOUT 秒以内に到着しない場合は、完了としてマークし、新しい要求の実行を許可します

ここでの私の主な問題は次のとおりです。

  • タスクタイムアウトを簡単に実装する方法
  • スレッド同期を使用せずに実装することは可能ですか (たとえば、イベント ループを使用しますか?)
  • それを実装するのに役立つ既存のライブラリはありますか? コア機能を柔軟に変更する必要があるため (生のソケットの使用、DNS ヘッダー フィールドの変更など)、既存の dns やネットワーク ライブラリを使用したくないことに注意してください。
4

2 に答える 2

0

aiodnsパッケージは試しましたか?https://pypi.python.org/pypi/aiodns/

タイムアウトの場合、asyncio には標準のwait_forコルーチンがあります ( https://docs.python.org/3/library/asyncio-task.html#asyncio.wait_for )。

于 2014-09-21T16:46:34.657 に答える
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()
于 2014-09-28T14:43:46.457 に答える