2

ソケットと便利な非同期バックエンドの使い方を学ぼうとしています。私はasyncoreを使ってPythonで始めました。さまざまなオンライン投稿を読んだ後、私は非常に単純なチャットサーバーと接続クライアントを作成しました。これを以下に再現します。

うまくいくようです。Pythonインタラクティブセッションを開いて、次のように入力します

> import chatserver
> server = chatserver.EchoServer('localhost', 7667)
> server.serve()

次に、別のIPythonインタラクティブセッションを開いて、次のように入力します

> import chatserver
> cxn = chatserver.Connection()
> cxn._connect('localhost', 7667)

これを行うと、接続が確立されたことを示すログ出力がサーバーウィンドウに表示されます。良い。次に入力します

> cxn.say('hi')

しばらくの間何も起こらず、その後、サーバーとクライアントのログメッセージが期待どおりに表示されます。

  1. この遅延が発生するのはなぜですか?
  2. ログ機能を正しく使用していますか?
  3. スレッド化を使用して、非同期ループが接続のために機能している間にインタラクティブセッションを使用できるようにしました。私はこれを合理的な方法で行いましたか?
  4. (オプション)self.out_buffer=""Connection._connect関数に行を含めないと、.out_bufferが存在しないというエラーが表示されます。これはどうしたの?
import asyncore
import socket
import logging
import threading
logging.basicConfig(level=logging.DEBUG, format="%(created)-15s %(msecs)d %(levelname)8s %(thread)d %(name)s %(message)s")
log = logging.getLogger(__name__)

class Connection(asyncore.dispatcher_with_send):
    def __init__(self):
        asyncore.dispatcher.__init__(self)

    def _connect(self, host, port, timeout=5, password=None):
        self.host = host
        self.port = port
        self.out_buffer=""
        self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect((host, port))
        #Run the asyncore loop in its own thread so that we can use the interactive session
        self.loop = threading.Thread(target=asyncore.loop)
        self.loop.daemon = True
        self.loop.start()

    def say(self, msg):
        self.out_buffer = msg

    def handle_read(self):
        data = self.recv(4096)
        log.debug('Received %s'%data)

class EchoHandler(asyncore.dispatcher_with_send):

    def handle_read(self):
        log.debug("handle_read")
        data = self.recv(1024)
        log.debug("after recv")
        if data:
            log.debug("got data: %s"%data)
            self.out_buffer = data
        else:
            log.debug("got null data")

class EchoServer(asyncore.dispatcher):
    SOCKET_TYPE = socket.SOCK_STREAM
    ADDRESS_FAMILY = socket.AF_INET
    def __init__(self, host, port):
        self.address = (host,port)
        asyncore.dispatcher.__init__(self)
        self.create_socket(self.ADDRESS_FAMILY, self.SOCKET_TYPE)
        log.debug("bind address=%s %s"%(host,port))
        self.bind(self.address)
        self.listen(1)

    def fileno(self):
        return self.socket.fileno()

    def serve(self):
        asyncore.loop()
        #Start asyncore loop in new thread
#        self.loop = threading.Thread(target=asyncore.loop)
#        self.loop.daemon = True
#        self.loop.start()

    def handle_accept(self):
        """Deal with a newly accepted client"""
        (connSock, clientAddress) = self.accept()
        log.info("conn made: clientAddress=%s %s"%(clientAddress[0], clientAddress[1]))
        #Make a handler for this connection
        EchoHandler(connSock)

    def handle_close(self):
        self.close()
4

2 に答える 2

1

asyncore.dispatcher_with_send呼び出しに依存している非同期ドキュメントを見るsend()と、デフォルトのタイムアウトasyncore.loop()は30秒です。これは遅延を説明するかもしれません。

于 2012-12-31T13:23:00.420 に答える
0

問題はEeroが示唆したとおりだったことがわかりました。

私は2つの変更を加えました:

EchoServerで

asyncore.loop()asyncore.loop(timeout=0.1)

接続

self.loop = threading.Thread(target=asyncore.loop)self.loop = threading.Thread(target=asyncore.loop, kwargs={'timeout':0.1})

応答がはるかに速くなりました。これはハックのようですが、誰かが同じ効果を適切な方法で得る方法を説明できる場合は、貢献してください。

于 2012-12-31T23:05:32.553 に答える