You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 03:55:27