Python3.4中xmlrpc.server保持TCP长连接的实现方案咨询
针对你的问题,我有两个可行的解决方案,分别对应你提到的「保持TCP连接」和「用ThreadingMixIn挂起请求」的思路,下面详细说明:
方案一:复用TCP连接(减少连接建立延迟)
默认情况下,xmlrpc.client.ServerProxy每次调用接口时都会创建新的HTTP连接,这就是你看到延迟的核心原因。要解决这个问题,我们可以显式创建一个Transport实例并复用它,同时让服务端支持HTTP Keep-Alive,这样就能在多次调用间保持TCP连接。
客户端代码修改
import xmlrpc.client as xc # 创建一个Transport实例,用于复用连接 transport = xc.Transport() # 传入transport参数给ServerProxy,确保所有调用复用同一个连接 server = xc.ServerProxy(f"http://{host_IP}:8000", transport=transport) var = False while isinstance(var, bool): var = server.pull_update() # 处理返回的数据或继续等待
服务端代码修改
默认的SimpleXMLRPCRequestHandler使用HTTP/1.0,而HTTP/1.0默认不开启Keep-Alive,我们需要自定义Handler切换到HTTP/1.1:
from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler class KeepAliveRequestHandler(SimpleXMLRPCRequestHandler): # 启用HTTP/1.1,默认支持Keep-Alive protocol_version = "HTTP/1.1" # 创建服务器时指定自定义Handler server = SimpleXMLRPCServer(("0.0.0.0", 8000), requestHandler=KeepAliveRequestHandler) # 注册你的函数 server.register_function(server.export_pull_update, "pull_update") server.serve_forever()
注意事项
- 这种方式只是复用TCP连接,你的轮询逻辑不需要改动,适合不想大幅修改现有代码的场景。
- 如果连接长时间空闲,可能会被中间网络设备(防火墙、路由器)主动断开,不过
Transport会自动重新建立连接,对上层逻辑透明。
方案二:基于ThreadingMixIn实现请求挂起(避免轮询)
如果你的场景允许客户端等待直到条件满足,而非反复轮询,那更高效的方式是让服务端的请求处理线程挂起,直到条件达成再返回结果。这时候需要用ThreadingMixIn让服务器支持多线程,避免单个请求阻塞所有客户端。
服务端代码修改
我们用线程条件变量来实现等待/唤醒逻辑:
from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler from socketserver import ThreadingMixIn import threading # 继承ThreadingMixIn实现多线程服务器 class ThreadedXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer): pass class MyServer(ThreadedXMLRPCServer): def __init__(self, addr): super().__init__(addr, requestHandler=SimpleXMLRPCRequestHandler) self.var = None # 存储要返回的更新数据 self.condition = threading.Condition() # 条件变量,用于线程同步 def export_pull_update(self): with self.condition: # 循环等待直到条件满足(防止虚假唤醒) while not self._check_condition(): self.condition.wait() return self.var def _check_condition(self): # 替换成你的实际条件判断逻辑 return self.var is not None # 当有新数据时调用此方法,唤醒所有等待的客户端 def set_new_data(self, new_data): with self.condition: self.var = new_data self.condition.notify_all() # 启动服务器 server = MyServer(("0.0.0.0", 8000)) server.register_function(server.export_pull_update, "pull_update") server.serve_forever()
客户端代码修改
此时客户端只需要调用一次接口,就会阻塞等待直到服务端返回数据,无需轮询:
import xmlrpc.client as xc server = xc.ServerProxy(f"http://{host_IP}:8000") # 调用一次就会等待直到条件满足 var = server.pull_update() # 处理返回的更新数据
注意事项
- 这种方式彻底消除了轮询和重复连接的开销,效率更高,但需要修改服务端的逻辑来管理条件变量和数据更新。
- 因为用了多线程,所有访问共享数据(比如
self.var)的操作都要通过条件变量或锁来保证线程安全,避免竞态条件。
方案选择建议
- 如果你的业务逻辑必须保留轮询(比如需要定期检查其他状态),优先选方案一,改动小且能有效降低连接延迟。
- 如果客户端可以等待直到条件满足,推荐方案二,它更高效,也更符合"按需返回"的设计思路。
内容的提问来源于stack exchange,提问作者Xialeth
相关产品推荐
相关产品推荐

