Python3实现RPC

RPC,RPC(Remote Procedure Call)是指远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

它是一种远程调用函数接口的方式,客户端和服务端之间约定一种契约(函数接口),然后服务端一直等待客户端的调用。有点像平常的WEB网络请求,不过这种方式非常轻量,不涉及HTTP这些东西,待会可以看到实现很简单。

上面说了,一种用途是在多台服务器之间互相进行调用,另一个用途则在于,不同编程语言之间都支持这种方式,像Python更是内置对其的支持,不需要额外安装什么库,所以可以直接在多语言的服务器之间互相进行调用,很简单。

xmlrpc库

在Python2中,服务端需要用到SimpleXMLRPCServer库,客户端需要用到ServerProxy库,而在Python3中,两者被整合到了同一个xmlrpc库中,分为xmlrpc.serverxmlrpc.client两部分。所以如果在Python3下使用,就需要导入这个库了。

1. 简单的服务器端

服务器端像web请求一样,需要确定供客户端访问的url和端口号,以及供客户端调用的方法实现,最后要让我们服务器一直处于等待被访问的状态,下面服务器简单实现返回当前时间,源文件:server.py -

import datetime
from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client

def today():
    today = datetime.datetime.today()
    return xmlrpc.client.DateTime(today)

server = SimpleXMLRPCServer((localhost, 8000))
print(Listening on port 8000...)
server.register_function(today, today)
server.serve_forever()

创建客户端,调用服务器端过程得到当前时间。源文件:client.py -

import xmlrpc.client
import datetime

proxy = xmlrpc.client.ServerProxy(http://localhost:8000/)

today = proxy.today()
# convert the ISO8601 string to a datetime object
converted = datetime.datetime.strptime(today.value, %Y%m%dT%H:%M:%S)
print(Today: %s % converted.strftime(%d.%m.%Y, %H:%M))

首先运行 server.py,然后再运行client.py,得到以下结果 -

示例2

二进制对象的示例用法。在下面这个示例中,要通过XMLRPC传输图片:

源文件:server.py -

from xmlrpc.server import SimpleXMLRPCServer
import xmlrpc.client

def python_logo():
    with open(python_logo.jpg, rb) as handle:
        return xmlrpc.client.Binary(handle.read())

server = SimpleXMLRPCServer((localhost, 8000))
print(Listening on port 8000...)
server.register_function(python_logo, 'python_logo')

server.serve_forever()

源文件:client.py -

import xmlrpc.client

proxy = xmlrpc.client.ServerProxy(http://localhost:8000/)
with open(/home/jb51/jb51-logo.jpg, wb) as handle:
    handle.write(proxy.python_logo().data)

示例3

MultiCall对象提供了一种将对远程服务器的多个调用封装到单个请求中的方法。下面是该类的用法示例。

服务器源文件:server.py -

from xmlrpc.server import SimpleXMLRPCServer

def add(x, y):
    return x + y

def subtract(x, y):
    return x - y

def multiply(x, y):
    return x * y

def divide(x, y):
    return x // y

# A simple server with simple arithmetic functions
server = SimpleXMLRPCServer((localhost, 8000))
print(Listening on port 8000...)
server.register_multicall_functions()
server.register_function(add, 'add')
server.register_function(subtract, 'subtract')
server.register_function(multiply, 'multiply')
server.register_function(divide, 'divide')
server.serve_forever()

客户端源文件:client.py -

import xmlrpc.client

proxy = xmlrpc.client.ServerProxy(http://localhost:8000/)
multicall = xmlrpc.client.MultiCall(proxy)
multicall.add(7, 3)
multicall.subtract(7, 3)
multicall.multiply(7, 3)
multicall.divide(7, 3)
result = multicall()

print(7+3=%d, 7-3=%d, 7*3=%d, 7//3=%d % tuple(result))