一、基于 JSON 的 RPC
jsonrpclib
XMLRPC 是基于 XML 格式进行数据传输的,当然 Python 中也有支持 JSON 格式的 RPC 库,jsonrpclib 就是一个基于 JSON 编码格式的 RPC 库,但它不是 Python 自带的库,需要通过 pip
进行安装。
pip install jsonrpclib-pelix -i https://pypi.douban.com/simple 复制代码
创建 json_rpc_server.py 文件,在该文件中定义一个 server 服务端,输入如下代码后启动服务端。
from jsonrpclib.SimpleJSONRPCServer import SimpleJSONRPCServer json_rpc_server = SimpleJSONRPCServer(("localhost", 8000)) # 注册 pow,幂运算,实际调用的是已有的算数pow() json_rpc_server.register_function(pow) # 注册自定义的 add 函数 def add(x, y): return x + y json_rpc_server.register_function(add, 'add') # 注册 fun 实例 class Fun: def div(self, x, y): return x // y fun = Fun() json_rpc_server.register_instance(fun) json_rpc_server.serve_forever() 复制代码
创建 json_rpc_client.py,定义一个客户端并调用在服务端注册的服务。
import jsonrpclib server = jsonrpclib.ServerProxy("http://localhost:8000") print(server.add(2,3)) print(server.pow(2, 3)) print(server.div(4, 2)) 复制代码
执行客户端代码,输出结果如下:
5 8 2 复制代码
从上面服务端和客户端的代码结构可以看出 SimpleJSONRPCServer 的代码与 Python 标准库 SimpleXMLRPCServer 的代码结构非常类似,包括类名以及注册服务的函数名都非常相似。
多线程调用
无论是基于 XML 格式还是 JSON 格式传输数据,作为一个 Web 服务是必须要应对并发的情况,接下来将会以 SimpleJSONRCPServer 为例来编写一个可以处理多个连接的 RPC 服务。
创建能够接收多线程的服务端,服务端启动时使用的是 PoolJSONRPCServer,并且在服务关闭时需要将相关的线程池也一并关闭。
# filename: threads_rpc_server.py from jsonrpclib.SimpleJSONRPCServer import PooledJSONRPCServer from jsonrpclib.threadpool import ThreadPool # 创建两个线程池 pool1 = ThreadPool(max_threads=10, min_threads=1) pool2 = ThreadPool(max_threads=50, min_threads=10) # 启动线程池 pool1.start() pool2.start() # 创建服务 server = PooledJSONRPCServer(('localhost', 8000), thread_pool=pool2) server.set_notification_pool(pool1) # 定义一个服务 def multi(x, y): return x * y # 注册一个服务 server.register_function(multi) # 关闭线程池 try: server.serve_forever() finally: pool1.stop() pool2.stop() server.set_notification_pool(None) 复制代码
创建一个单线程的客户端调用服务端的 multi 函数。
import jsonrpclib server = jsonrpclib.ServerProxy('http://localhost:8000') print(server.multi(1, 2)) # 2 复制代码
再次创建一个客户端,使用多线程进行调用服务端注册的服务
import jsonrpclib import threading def call_multi(x, y): server = jsonrpclib.ServerProxy('http://localhost:8000') print(server.multi(x, y)) for i in range(5): thread = threading.Thread(target=call_multi(i, i+1)) thread.start() 复制代码
在服务端代码保持不变并且已经被启动的前提下,运行多线程的客户端,输出结果如下:
0 2 6 12 20 复制代码
更多关于 jsonroclib 的应用可以参考 GitHub。