非常简单的python客户端/服务器工作,但奇怪的延迟

时间:2012-12-31 12:00:14

标签: python sockets asynchronous

我正在尝试学习如何使用套接字和一个有用的异步后端。我用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. 我使用线程来制作它,以便我可以使用交互式会话,而asyncore循环对Connection来说就是这样。我是否以合理的方式做到了这一点?
  4. (可选)如果我在Connection._connect函数中没有包含行self.out_buffer="",则会收到错误消息,指出.out_buffer不存在。怎么了?
  5. 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()
    

2 个答案:

答案 0 :(得分:1)

查看asyncore文档,您依靠asyncore.dispatcher_with_send来调用send()asyncore.loop()的默认超时为30秒。这可以解释延迟。

答案 1 :(得分:0)

事实证明问题与Eero建议的一样。

我做了两处修改:

在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})

现在响应速度更快。这看起来像是一个黑客,但如果有人可以解释一种方法以正确的方式获得相同的效果,请做出贡献。