Python-xmlrpc

xmlrpc库

在Python2(网上大部分是Python2使用RPC的资料)中,服务端需要用到SimpleXMLRPCServer库,客户端需要用到ServerProxy库,而在Python3中,两者被整合到了同一个xmlrpc库中,分为xmlrpc.server和xmlrpc.client两部分。所以如果在Python3下使用,就需要导入这个库了。

简单的服务器端

服务器端需要做什么呢?

像web请求一样,我们需要确定供客户端访问的url和端口号,以及供客户端调用的方法实现,最后要让我们服务器一直处于等待被访问的状态:

# _*_ coding:utf-8 _*_

from xmlrpc.server import SimpleXMLRPCServer

# 调用函数
def respon_string(str):
    return "get string:%s"%str


if __name__ == '__main__':
    server = SimpleXMLRPCServer(('localhost', 8888)) # 初始化
    server.register_function(respon_string, "get_string") # 注册函数
    print ("Listening for Client")
    server.serve_forever() # 保持等待调用状态

可以看到,代码中就实现了上面说的几点。register_function用于注册一个供调用的函数,第一个参数为自己实现的方法名,第二个参数为供客户端调用的方法名。

简单的客户端

客户端要做的就更少了:根据url和端口号初始化一个服务器对象,然后调用需要的方法即可:

# _*_ coding:utf-8 _*_

from xmlrpc.client import ServerProxy

if __name__ == '__main__':
    server = ServerProxy("http://localhost:8888") # 初始化服务器
    print (server.get_string("cloudox")) # 调用函数并传参

这时候我们用两个终端来跑服务端和客户端,就可以看到效果了:

服务端启动并保持监听

客户端远程调用了多次

从图中可以看到,服务器每次被访问都会打印出访问来源。而客户端访问后,会远程调用在服务端运行的函数具体实现。

多线程访问

上面的方法只能供单线程访问,但大多数情况下都需要支持多线程,该怎么处理呢?很简单,只需要更改一下服务端即可:

# _*_ coding:utf-8 _*_

from xmlrpc.server import SimpleXMLRPCServer
from socketserver import ThreadingMixIn


class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass

# 调用函数1
def respon_string(str):
    return "get string:%s"%str

# 调用函数2
def add(x, y):
    return x + y


if __name__ == '__main__':
    server = ThreadXMLRPCServer(('localhost', 8888)) # 初始化
    server.register_function(respon_string, "get_string") # 注册函数1
    server.register_function(add, 'add') # 注册函数2
    print ("Listening for Client")
    server.serve_forever() # 保持等待调用状态

代码中我们初始化服务器用的不再是SimpleXMLRPCServer了,而是自定义的一个类,继承自两个基类,ThreadingMixIn使其能够支持多线程,其余的操作方式还是和普通的一样。并且我们新增了一个函数,接受两个参数,计算和,可以看到无论参数数量多少,我们注册函数的时候都只写函数名。

客户端代码如下:

# _*_ coding:utf-8 _*_

from xmlrpc.client import ServerProxy

if __name__ == '__main__':
    server = ServerProxy("http://localhost:8888") # 初始化服务器
    print (server.get_string("cloudox")) # 调用函数1并传参
    print (server.add(8, 8)) # 调用函数2并传参

客户端调用两个函数的结果

多线程的效果这里没法展示,不过两个函数的调用都成功了。

文件上传&下载

RPC除了传参以外还可以在客户端与服务器之间传输文件——客户端既可以从服务器下载文件,也可以上传文件到服务器。

传输文件要用到xmlrpc.client.Binary这个库,如果要实现从服务器下载文件的功能,那么服务器端也需要导入这个库,即使它名义上属于client库。

传输文件的基本步骤是:

  • 用open打开一个文件(没有的话会创建),确定是读权限还是写权限;
  • 在文件发送端通过调用xmlrpc.client.Binary来进行文件的传输,接收端通过值.data来获取内容(详见代码);
  • 关闭文件。

服务器:

# _*_ coding:utf-8 _*_

from xmlrpc.server import SimpleXMLRPCServer
from socketserver import ThreadingMixIn
import xmlrpc.client


class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass


# 供客户端下载文件
def image_get():
    handle = open("boy.jpg", 'rb')
    return xmlrpc.client.Binary(handle.read())


# 供客户端上传文件
def image_put(data):
    handle = open("get_girl.jpg", 'wb')
    handle.write(data.data)
    handle.close()


if __name__ == '__main__':
    server = ThreadXMLRPCServer(('localhost', 8888), allow_none=True) # 初始化
    server.register_function(image_put, 'image_put')
    server.register_function(image_get, 'image_get')
    print ("Listening for Client")
    server.serve_forever() # 保持等待调用状态

代码中初始化服务器时多了个参数allow_none=True,这是允许不返回参数给客户端,因为文件上传的函数都是没有返回值的,不设置这个参数会报错,实际上这里也应该返回一个值告诉客户端是否上传成功。

文件上传的代码中可以看到,写入的是data.data,单单data是会报错的,因为实际上要写入的是Binary.data,这在下面的客户端代码下载文件时也会看到。

客户端:

from xmlrpc.client import ServerProxy
import xmlrpc.client

if __name__ == '__main__':
    server = ServerProxy("http://localhost:8888", allow_none=True)
    # 上传文件
    put_handle = open("girl.jpg", 'rb')
    server.image_put(xmlrpc.client.Binary(put_handle.read()))
    put_handle.close()
    # 下载文件
    get_handle = open("get_boy.jpg", 'wb')
    get_handle.write(server.image_get().data)
    get_handle.close()

可以看到,下载文件时写入的也是获取到的返回值.data,而不是返回值本身,这个一定要注意。

可以查看一下代码目录,会发现文件传输(上传&下载都在一个目录下)成功了:

文件传输结果

以上,就是Python3使用xmlrpc的方式了,可以看到,确实很简单的可以实现远程调用,虽然这里都在一台机器上,不过要支持远程只需要改变IP就可以了。这比搭建一个WEB后台服务器要简单多了,如果只是要实现简单的函数调用,用RPC会节省不少功夫。



作者:Cloudox_
链接:https://www.jianshu.com/p/9987913cf734
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

猜你喜欢

转载自blog.csdn.net/weixin_38278993/article/details/89303497