Skip to main content
 首页 » 编程设计

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

2025年05月04日8myhome

我正在尝试学习如何使用套接字和有用的异步后端。我开始使用 python 和 asyncore。在阅读了各种在线帖子后,我编写了一个非常简单的聊天服务器和连接客户端,转载如下。

这似乎有效。我打开一个 python 交互式 session 并键入

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

然后我打开另一个 IPython 交互式 session 并输入

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

当我这样做时,我在服务器窗口中得到一个日志输出,表明连接已经建立。好的。然后我输入

> cxn.say('hi') 

一段时间没有任何反应,然后日志消息按预期显示给服务器和客户端。

  1. 为什么会出现这种延迟?
  2. 我是否正确使用了日志功能?
  3. 我使用线程实现它,这样我就可以使用交互式 session ,而 asyncore 循环为 Connection 做这件事。我这样做是否合理?
  4. (可选)如果我不在 Connection._connect 函数中包含 self.out_buffer="" 行,我会收到一条错误消息,指出 .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() 

请您参考如下方法:

查看您依赖 asyncore.dispatcher_with_send 调用 send() 和 asyncore.loop() 的默认超时的 asyncore 文档> 是 30 秒。这可以解释延迟。