有勇气的牛排博客
☰

python标准库xmlrpc 之RPC远程方法调用

有勇气的牛排 1358 Python 2023-05-18 21:08:06

知止自律打卡-微信小程序APP
一款微信自律打卡小程序,支持自定义打卡项目、习惯记录、项目日记、专注计时与数据统计。自律打卡、学习打卡、读书打卡、健身打卡、运动打卡、减肥打卡、戒色打卡、养生打卡、戒烟、戒酒、戒熬夜等多种场景。万能打卡模板自由创建。可自定义每日打卡目标,记录习惯连续天数,可视化追踪成长进度。
了解产品详情 →
微信搜索「知止自律打卡」
知止自律打卡微信小程序

<font face=" 楷体,华文行楷,隶书,黑体" color=black size=4>💖💖💖养成每日阅读好习惯, 每天进步, 超越昨天的自己💖💖💖</font>
<font face=" 楷体,华文行楷,隶书,黑体" color=#9400D3 size=3>愿景:输出体系化编程知识与技巧,助力软件行业发展与从业者学习减负,让编程产生更大价值。</font>

🔎🔎🔎
Python 专栏文章: 👉👉👉Python 文章专栏大全 | 有勇气的牛排👈👈👈
</font>

<font face=" 楷体,华文行楷,隶书,黑体" color=red size=5>大家好,我是有勇气的牛排🐮🐮🐮 </font>
<font face=" 楷体,华文行楷,隶书,黑体" color=blue size=5>有问题的小伙伴欢迎在文末评论,点赞、收藏是对我最大的支持!!!</font>

一、前言🐮

Remote Procedure Call即RPC(远程方法调用),它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。并且被多重语言支持,故能在多种语言的服务器中相互调用。

RPC采用客户机/服务器模式。请求程序即为客户机,服务程序为服务端。首先由客户端发起一个远程调用并等待,然后由服务端进行处理、计算并应答,结束后进入睡眠状态,客户端继续进行运行。

二、 ServerProxy 对象🐮

ServerProxy 实例有一个方法与 XML-RPC 服务器所接受的每个远程过程调用相对应。 调用该方法会执行一个 RPC,通过名称和参数签名来调度(例如同一个方法名可通过多个参数签名来重载)。 RPC 结束时返回一个值,它可以是适用类型的返回数据或是表示错误的 Fault 或 ProtocolError 对象。

1、简单的搭建

(1)server

from xmlrpc.server import SimpleXMLRPCServer

rpc_server = "127.0.0.1"
rpc_port = 8000

def get_name(name):
    res = f"名字:{name}"
    return res


server = SimpleXMLRPCServer((rpc_server, rpc_port))
print("Listening on port 8000...")

server.register_function(get_name, "get_name")

# 保持等待调用状态
server.serve_forever()

(2)client

import xmlrpc.client

rpc_server = "127.0.0.1"
rpc_port = 8000

proxy = xmlrpc.client.ServerProxy(f"http://{rpc_server}:{rpc_port}/")

print(str(proxy.get_name("有勇气的牛排")))
# 输出:名字:有勇气的牛排

2、 支持多线程

(1)server

多线程
自定义类ThreadXMLRPCServer,继承两个基类,ThreadingMixIn, SimpleXMLRPCServer
ThreadingMixIn:帮助支持多线程
SimpleXMLRPCServer:RPC支持

from xmlrpc.server import SimpleXMLRPCServer
from socketserver import ThreadingMixIn

rpc_server = "127.0.0.1"
rpc_port = 8000


class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    """
        多线程
        自定义类ThreadXMLRPCServer,继承两个基类,ThreadingMixIn, SimpleXMLRPCServer
        ThreadingMixIn:帮助支持多线程
        SimpleXMLRPCServer:RPC支持
    """
    pass


def get_name(name):
    res = f"名字:{name}"
    return res


if __name__ == '__main__':
    # 多线程 class ThreadXMLRPCServer
    server = ThreadXMLRPCServer((rpc_server, rpc_port))

    print("Listening on port 8000...")

    # 注册函数
    server.register_function(get_name, "get_name")

    # 保持等待调用状态
    server.serve_forever()

(2)client

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

from xmlrpc.client import ServerProxy

rpc_server = "127.0.0.1"
rpc_port = 8000

if __name__ == '__main__':
    # 初始化服务器
    proxy = ServerProxy(f"http://{rpc_server}:{rpc_port}/")

    # 调用函数 get_name
    res = str(proxy.get_name("有勇气的牛排"))
    print(res)

三、DateTime 对象🐮

该类的初始化可以使用距离 Unix 纪元的秒数、时间元组、ISO 8601 时间/日期字符串或 datetime.datetime 实例。

server

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

rpc_server = "127.0.0.1"
rpc_port = 8000


class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass


# DateTime 对象
def get_server_time():
    today = datetime.today()
    return xmlrpc.client.DateTime(today)

if __name__ == '__main__':
    # 多线程 class ThreadXMLRPCServer
    server = ThreadXMLRPCServer((rpc_server, rpc_port), allow_none=True)
    print("Listening on port 8000...")

    server.register_function(get_server_time, "get_server_time")

    # 保持等待调用状态
    server.serve_forever()

client

from datetime import datetime
from xmlrpc.client import ServerProxy

rpc_server = "127.0.0.1"
rpc_port = 8000

if __name__ == '__main__':
    server = ServerProxy(f"http://{rpc_server}:{rpc_port}/")

    server_time = datetime.strptime(server.get_server_time().value, "%Y%m%dT%H:%M:%S")
    print(server_time)

image.png

四、Binary 对象🐮

RPC除了互相串参数外,文件也是可以传的,即上传与下载。我们这里可以使用Binary对象即可实现。

该类的初始化可以使用字节数据(可包括 NUL)。

server

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

rpc_server = "127.0.0.1"
rpc_port = 8000


class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass


# 提供客户端下载文件
def get_file():
    handle = open("test.txt", 'rb')
    return xmlrpc.client.Binary(handle.read())


# 提供客户端上传文件
def put_file(data):
    handle = open(f"./tmp/test.txt", "wb")
    handle.write(data.data)
    handle.close()


if __name__ == '__main__':
    # 多线程 class ThreadXMLRPCServer
    server = ThreadXMLRPCServer((rpc_server, rpc_port), allow_none=True)
    # server = SimpleXMLRPCServer((rpc_server, rpc_port))
    print("Listening on port 8000...")

    # 注册函数
    server.register_function(get_file, "get_file")
    server.register_function(put_file, "put_file")

    # 保持等待调用状态
    server.serve_forever()

client

from xmlrpc.client import ServerProxy
import xmlrpc.client

rpc_server = "127.0.0.1"
rpc_port = 8000

if __name__ == '__main__':
    server = ServerProxy(f"http://{rpc_server}:{rpc_port}/")

    # 上传文件
    put_handle = open("test.txt", 'rb')
    server.put_file(xmlrpc.client.Binary(put_handle.read()))
    put_handle.close()

    # 下载文件
    # get_handle = open("./tmp/test.txt", 'wb')
    # get_handle.write(server.get_file().data)
    # get_handle.close()

五、报错🐮

<Fault 1: "<class 'TypeError'>:cannot marshal None unless allow_none is enabled"

添加allow_none=True即可

server = ThreadXMLRPCServer((rpc_server, rpc_port), allow_none=True)

标签:

×
×