Python中用Paramiko实现XML-RPC over SSH报错:Transport无request属性
实现XML-RPC over SSH(Paramiko+xmlrpc)的正确方案
问题背景
尝试用Paramiko实现XML-RPC通过SSH通信时,调用XML-RPC方法触发AttributeError: 'Transport' object has no attribute 'request'错误。网络连接和库安装正常,SSH连接可建立,但Paramiko返回的Transport对象与xmlrpc.client要求的Transport接口不兼容。
错误原因
xmlrpc.client.ServerProxy的transport参数需要的是实现了xmlrpc.client.Transport抽象接口的对象(必须包含request方法),而Paramiko的Transport是SSH传输层控制对象,两者接口完全不同,直接传入会导致调用未定义方法的错误。
解决方案1:SSH端口转发(推荐,实现简单)
通过SSH建立本地端口到远程XML-RPC服务端口的转发,让本地XML-RPC客户端连接本地转发端口,间接访问远程服务。
修改后的客户端代码
import paramiko import xmlrpc.client import getpass # 配置参数 REMOTE_HOST = "your_hostname" REMOTE_XMLRPC_PORT = 8000 # 远程XML-RPC服务监听的端口 LOCAL_FORWARD_PORT = 9000 # 本地映射端口 USERNAME = "username" PASSWORD = getpass("Enter password:") # 初始化SSH客户端 ssh = paramiko.SSHClient() ssh.load_system_host_keys() ssh.connect(REMOTE_HOST, username=USERNAME, password=PASSWORD) # 建立端口转发:本地LOCAL_FORWARD_PORT -> 远程127.0.0.1:REMOTE_XMLRPC_PORT # 注意:如果远程XML-RPC服务绑定的是0.0.0.0,这里可以用REMOTE_HOST,否则用127.0.0.1 ssh.get_transport().open_channel( 'direct-tcpip', ('127.0.0.1', REMOTE_XMLRPC_PORT), ('127.0.0.1', LOCAL_FORWARD_PORT) ) # 连接本地转发端口,发起XML-RPC请求 xmlrpc_client = xmlrpc.client.ServerProxy(f"http://127.0.0.1:{LOCAL_FORWARD_PORT}") result = xmlrpc_client.your_method_name() print(result) # 关闭连接 ssh.close()
服务器端代码(无需修改,注意绑定地址)
如果远程XML-RPC服务只监听127.0.0.1,端口转发刚好能访问;如果要允许外部访问,可以修改绑定地址为0.0.0.0:
from xmlrpc.server import SimpleXMLRPCServer # 绑定0.0.0.0允许所有地址访问,或者127.0.0.1仅本地访问 server = SimpleXMLRPCServer(("0.0.0.0", 8000)) def your_method_name(): return "hello, world!" server.register_function(your_method_name) server.serve_forever()
解决方案2:自定义XML-RPC Transport(基于Paramiko通道)
实现一个符合xmlrpc.client.Transport接口的自定义类,使用Paramiko的SSH通道来传输XML-RPC请求和响应。
自定义Transport类及客户端代码
import paramiko import xmlrpc.client import getpass from io import BytesIO class SSHXMLRPCTransport(xmlrpc.client.Transport): def __init__(self, ssh_client, remote_host, remote_port): super().__init__() self.ssh_client = ssh_client self.remote_host = remote_host self.remote_port = remote_port self.channel = None def make_connection(self, host): # 建立SSH通道连接到远程XML-RPC端口 self.channel = self.ssh_client.get_transport().open_channel( 'direct-tcpip', (self.remote_host, self.remote_port), ('127.0.0.1', 0) ) return self def send_request(self, host, handler, request_body, debug): # 发送XML-RPC请求 self.channel.send(request_body) # 读取响应(简单实现,实际可根据需求优化分块逻辑) response = b"" while not self.channel.closed: chunk = self.channel.recv(4096) if not chunk: break response += chunk return response def parse_response(self, response): # 解析XML-RPC响应 return super().parse_response(BytesIO(response)) # 配置参数 REMOTE_HOST = "your_hostname" REMOTE_XMLRPC_PORT = 8000 USERNAME = "username" PASSWORD = getpass("Enter password:") # 初始化SSH客户端 ssh = paramiko.SSHClient() ssh.load_system_host_keys() ssh.connect(REMOTE_HOST, username=USERNAME, password=PASSWORD) # 使用自定义Transport创建XML-RPC客户端 transport = SSHXMLRPCTransport(ssh, REMOTE_HOST, REMOTE_XMLRPC_PORT) xmlrpc_client = xmlrpc.client.ServerProxy(f"http://{REMOTE_HOST}:{REMOTE_XMLRPC_PORT}", transport=transport) # 调用方法 result = xmlrpc_client.your_method_name() print(result) # 关闭资源 transport.channel.close() ssh.close()
内容的提问来源于stack exchange,提问作者bblais
相关产品推荐
相关产品推荐

