什么是 xmlrpclib?
xmlrpclib 是 Python 的标准库模块,用于实现 XML-RPC 协议。

-
XML-RPC 是什么? 它是一种简单的、基于 XML 的远程过程调用协议,它允许一个程序(客户端)在另一台计算机上(服务器)执行一个函数或方法,并通过 HTTP 协议传输数据,数据被编码成 XML 格式。
-
xmlrpclib的作用? 这个模块为 Python 程序提供了客户端和服务器端的工具,让你可以轻松地创建和使用 XML-RPC 服务。 -
重要提示:Python 3 的变化 在 Python 3 中,
xmlrpclib模块被重命名为xmlrpc.client,其功能和 API 基本保持一致,只是模块名变了。- Python 2:
import xmlrpclib - Python 3:
import xmlrpc.client
- Python 2:
在下面的讲解中,我们将主要以 Python 3 的 xmlrpc.client 为例,因为它代表了当前的标准。

核心概念
理解 XML-RPC 的几个关键点:
- 客户端/服务器模型:一个程序发起请求(客户端),另一个程序接收并处理请求(服务器)。
- 传输协议:通常使用 HTTP 或 HTTPS。
- 数据格式:请求和响应都使用 XML 格式。
- 数据类型:XML-RPC 定义了一组标准的数据类型,用于在不同语言间传递。
xmlrpc.client会自动将 Python 类型映射到 XML-RPC 类型,反之亦然。
| Python 类型 | XML-RPC 类型 |
|---|---|
int, long |
<int> |
float, double |
<double> |
boolean |
<boolean> |
str, unicode |
<string> |
bytes, bytearray |
<base64> |
list, tuple |
<array> |
dict |
<struct> (键必须是字符串) |
None |
<value><nil/></value> |
使用 xmlrpc.client (客户端)
客户端的主要工作是连接到 XML-RPC 服务器,并调用其上的方法。
基本步骤:
- 创建服务器代理:使用
ServerProxy类来创建一个代表远程服务器的对象,这个对象的方法调用会被自动转换成 XML-RPC 请求。 - 调用方法:像调用本地对象的方法一样调用
ServerProxy对象的方法。 - 处理响应和异常:服务器会返回一个结果或抛出一个异常。
示例:调用一个公开的 XML-RPC 服务器
一个经典的公开 XML-RPC 服务器是 Blogger API 的一个测试端点,我们用它来演示。
# Python 3
import xmlrpc.client
import sys
# 服务器的 URL
# 这是一个公开的、用于测试的 XML-RPC 服务器
server_url = "http://betty.userland.com/RPC2"
try:
# 1. 创建服务器代理
# allow_none=True 允许传输 None 值
proxy = xmlrpc.client.ServerProxy(server_url, allow_none=True)
# 2. 调用服务器的方法
# 这个服务器提供了一个名为 'stateName' 的方法,接受一个数字(州代码)并返回州名
print("正在连接到服务器:", server_url)
# 调用 'stateName' 方法,参数是 5 (代表加州)
state_code = 5
state_name = proxy.stateName(state_code)
print(f"州代码 {state_code} 对应的州是: {state_name}")
# 调用另一个方法 'examples.getStateName' (一些服务器使用命名空间)
# 这个方法接受一个字符串(州名)并返回其代码
state_name_to_find = "California"
state_code_returned = proxy.examples.getStateName(state_name_to_find)
print(f"州 '{state_name_to_find}' 的代码是: {state_code_returned}")
except xmlrpc.client.Fault as err:
# 3. 处理 XML-RPC 特定的错误 (方法不存在)
print("XML-RPC 错误 (Fault):", f"错误码: {err.faultCode}, 错误信息: {err.faultString}")
except xmlrpc.client.ProtocolError as err:
# 4. 处理 HTTP 协议级别的错误 (404 Not Found)
print("协议错误:", f"URL: {err.url}, HTTP/HTTPS 错误码: {err.errcode}, 错误信息: {err.errmsg}")
except ConnectionRefusedError:
# 5. 处理网络连接问题
print("连接被拒绝,请检查服务器地址和网络。")
except Exception as e:
# 处理其他未知错误
print(f"发生未知错误: {e}")
运行结果可能如下 (取决于服务器状态):

正在连接到服务器: http://betty.userland.com/RPC2
州代码 5 对应的州是: California
州 'California' 的代码是: 5
创建 XML-RPC 服务器 (使用标准库)
Python 的标准库也提供了一个简单的 xmlrpc.server 模块 (Python 2 中为 SimpleXMLRPCServer),可以让你快速创建一个 XML-RPC 服务器。
基本步骤:
- 创建服务器实例:使用
SimpleXMLRPCServer类,并指定服务器监听的地址和端口。 - 注册函数:使用
register_function方法将一个或多个 Python 函数注册为可远程调用的方法。 - 启动服务循环:调用
serve_forever()来启动服务器,让它等待并处理客户端请求。
示例:一个简单的加法服务器
server.py
# Python 3
from xmlrpc.server import SimpleXMLRPCServer
import threading
# 定义一个简单的加法函数
def add(x, y):
"""将两个数字相加"""
print(f"服务器收到加法请求: {x} + {y}")
if not isinstance(x, (int, float)) or not isinstance(y, (int, float)):
raise TypeError("参数必须是数字")
return x + y
# 定义一个获取时间的函数
def get_current_time():
"""返回当前服务器时间"""
import datetime
return str(datetime.datetime.now())
# 创建服务器实例,监听 localhost 的 8000 端口
# 注意:在生产环境中,应该使用 '0.0.0.0' 来允许外部访问,并考虑安全性
server = SimpleXMLRPCServer(('localhost', 8000), allow_none=True, logRequests=True)
# 注册函数
# 可以给函数起一个别名
server.register_function(add, 'add')
server.register_function(add, 'sum') # 'add' 和 'sum' 都指向同一个函数
server.register_function(get_current_time, 'get_time')
# 注册一个实例的所有公开方法 (以 '_' 开头的方法不会被注册)
class MyService:
def multiply(self, x, y):
return x * y
server.register_instance(MyService())
# 打印启动信息
print("启动 XML-RPC 服务器,监听端口 8000...")
print("可以使用 'http://localhost:8000' 来检查服务器状态 (如果支持)")
# 在单独的线程中运行服务器,这样主线程可以继续执行其他操作
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True # 设置为守护线程,主线程退出时它也退出
server_thread.start()
# 主线程可以做其他事情...
print("服务器已在后台运行,按 Ctrl+C 停止。")
try:
while True:
pass # 保持主线程存活
except KeyboardInterrupt:
print("\n正在关闭服务器...")
server.shutdown()
server.server_close()
print("服务器已关闭。")
client.py (客户端代码)
# Python 3
import xmlrpc.client
import time
# 连接到我们刚刚创建的服务器
proxy = xmlrpc.client.ServerProxy('http://localhost:8000')
try:
# 调用 'add' 方法
result = proxy.add(10, 25)
print(f"10 + 25 = {result}")
# 调用 'sum' 方法 (它是 'add' 的别名)
result_sum = proxy.sum(7, 8)
print(f"7 + 8 = {result_sum}")
# 调用 'get_time' 方法
current_time = proxy.get_time()
print(f"服务器当前时间: {current_time}")
# 调用实例方法 'multiply'
multiply_result = proxy.multiply(6, 7)
print(f"6 * 7 = {multiply_result}")
# 测试错误处理
# try:
# proxy.add("hello", "world") # 这会引发 TypeError
# except xmlrpc.client.Fault as err:
# print(f"捕获到预期错误: {err.faultString}")
except ConnectionRefusedError:
print("无法连接到服务器!请确保服务器正在运行。")
except Exception as e:
print(f"客户端发生错误: {e}")
如何运行:
- 首先运行
python server.py,你会看到服务器启动的消息。 - 然后在另一个终端窗口运行
python client.py,客户端会连接到服务器并打印结果。
安全性考量 (非常重要!)
标准的 SimpleXMLRPCServer 非常不安全,不应该直接暴露在公共互联网上。
- 没有身份验证:任何知道你服务器地址和端口的人都可以调用任何已注册的函数。
- 没有加密:所有数据都通过明文 HTTP 传输,可以被中间人窃听和篡改。
如何增强安全性?
-
使用 HTTPS:
- 最基本也是最重要的措施,将服务器改为使用
SimpleXMLRPCServer(('0.0.0.0', 443)),并配置 SSL 证书,客户端使用https://来连接。 - 在
xmlrpc.client中,你可以通过创建一个自定义的 transport 来处理 HTTPS。
- 最基本也是最重要的措施,将服务器改为使用
-
添加身份验证:
- 你可以在调用
register_function时,包装一个函数来检查请求的头部信息或用户名/密码。 - 一个更简单的方法是使用
register_function的name参数,并结合一个通用的认证装饰器。
- 你可以在调用
示例:简单的基于装饰器的认证
# server.py
from xmlrpc.server import SimpleXMLRPCServer
import functools
# 简单的认证装饰器
def require_auth(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# 在真实场景中,这里应该从请求中获取并验证 token 或用户名密码
# SimpleXMLRPCServer 没有直接提供获取请求对象的方法,这是一个简化的例子
# 更复杂的实现可能需要继承 SimpleXMLRPCRequestHandler
print("正在检查认证...")
# 假设我们通过一个特殊的参数来模拟认证
if 'auth_token' in kwargs and kwargs['auth_token'] == 'secret123':
return func(*args, **kwargs)
else:
raise xmlrpc.client.Fault(401, "认证失败")
return wrapper
@require_auth
def protected_add(x, y):
return x + y
server = SimpleXMLRPCServer(('localhost', 8001))
server.register_function(protected_add, 'protected_add')
print("带认证的启动服务器...")
server.serve_forever()
客户端调用时需要提供 auth_token:
# client.py
import xmlrpc.client
proxy = xmlrpc.client.ServerProxy('http://localhost:8001')
try:
# 正确调用
result = proxy.protected_add(5, 6, auth_token='secret123')
print(f"受保护的加法结果: {result}")
# 错误调用
result_fail = proxy.protected_add(1, 2, auth_token='wrong_token')
except xmlrpc.client.Fault as err:
print(f"捕获到认证错误: {err.faultString}")
现代替代方案
虽然 xmlrpc.client 很有用,但它现在被认为是一种较老的技术。
- JSON-RPC:与 XML-RPC 类似,但使用 JSON 作为数据格式,JSON 更轻量、解析速度更快,是目前更推荐的选择,Python 的
json模块非常成熟。 - REST (Representational State Transfer):使用 HTTP 动词 (GET, POST, PUT, DELETE) 和 URL 来操作资源,通常与 JSON 结合使用,REST 是现代 Web API 的绝对主流。
- gRPC:由 Google 开发,使用 Protocol Buffers 作为数据格式,性能极高,适合内部微服务通信。
| 特性 | 描述 |
|---|---|
| 模块名 | Python 2: xmlrpclib Python 3: xmlrpc.client |
| 用途 | 实现客户端和服务器端的 XML-RPC 通信。 |
| 客户端核心 | ServerProxy(url) 用于创建代理对象,调用其方法即可。 |
| 服务器核心 | SimpleXMLRPCServer 用于快速创建服务器,register_function 用于注册方法。 |
| 优点 | 简单易用,跨语言,有标准库支持。 |
| 缺点 | 性能相对较低,XML 格式冗余,安全性差(默认不加密、无认证)。 |
| 适用场景 | 内部工具、遗留系统集成、简单的远程过程调用,对于新项目,更推荐 REST 或 JSON-RPC。 |
对于任何新的项目,除非有特定的兼容性要求,否则都应该优先考虑使用更现代的 API 设计风格,如 REST,但对于理解和维护一些老旧系统,xmlrpc.client 仍然是一个非常重要的工具。
