python实现rpc框架_使用Python实现RPC框架
前言
本文将会使用Python实现一个最简单的RPC框架,玩具向,不具有实用意义,但可以让你清醒的理解RPC框架的几个组成部分,只是比看Python自带的xmlrpc清晰。
本文需要一点Python socket基础。
如果你对Python Socket基础方面的内容不是很熟悉,推荐阅读Real Python的「Socket Programming in Python (Guide)」
吐槽一下VSCode,在开发一些比较复杂的Python项目时,VSCode的debug功能让人感到蛋疼,询问了Windows下使用VSCode的同事,都没有这样的问题,不清楚VSCode对Mac的支持是否存在问题,还只是我单纯的不会用:(
本文代码比较简单,所以还是使用VSCode进行开发。那我们开始吧!
回顾RPC
客户端(Client):服务调用方。
客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
服务端(Server):服务的真正提供者。
Network Service:底层传输,可以是 TCP 或 HTTP。
实现jsonrpc
在实现前,简单理一下整体思路。
1.Network Service 直接使用Python Socket相关的API实现
2.传输数据使用JSON,在Socket层会被压成二进制,我们无需关心
模仿xmlrpc,Client与Server都采用Minix多继承机制来实现,每个类负责自身的事情,最终暴露出现的只有一个类中有限的方法。
先从Client端开始实现。
# client.py
import rpcclient
c = rpcclient.RPCClient()
c.connect('127.0.0.1', 5000)
res = c.add(1, 2, c=3)
print(f'res: [{res}]')
复制代码
实例化rpcclient.RPCClient类,然后调用connect方法链接Server端,随后直接调用Server端的add方法,该方法的效果就是将传入的数据进行累加并将累加的结果返回,最后将add方法返回的结果打印出了。
RPCClient类继承于TCPClient类与RPCStub类。
# rpclient.py
class RPCClient(TCPClient, RPCStub):
pass
复制代码
其中TCPClient负责通过Socket实现TCP链接并将数据请求过去,而RPCStub类主要将Client端调用Server端方法的相关信息打包,然后调用TCPClient类中的方法发送则可,两个类同样实现在rpclient.py文件中,代码如下。
class TCPClient(object):
def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def connect(self, host, port):
'''链接Server端'''
self.sock.connect((host, port))
def send(self, data):
'''将数据发送到Server端'''
self.sock.send(data)
def recv(self, length):
'''接受Server端回传的数据'''
return self.sock.recv(length)
class RPCStub(object):
def __getattr__(self, function):
def _func(*args, **kwargs):
d = {'method_name': function, 'method_args': args, 'method_kwargs': kwargs}
self.send(json.dumps(d).encode('utf-8')) # 发送数据
data = self.recv(1024) # 接收方法执行后返回的结果
return data
setattr(self, function, _func)
return _func
复制代码
TCPClient类就是常规的Socket API的操作,无需多言,主要看看RPCStub类。
当我们在Client端调用res = c.add(1, 2, c=3)时,会执行RPCStub中的__getattr__方法,该方法会将Client端调用的方法、参数等信息通过TCPServer类的send方法发送,发送数据进行了JSON格式化,方便Server端解码,随后便调用recv方法等待Server端相应的数据返回。
因为RPCClient类本身没有add方法,为了让用户做到Client端直接调用Server端方法的形式,先利用__getattr__构建了_func方法,并将其通过setattr方法设置到RPCClient类中,此时该类就有Server端方法对应的映射了。
调用add方法,就调用了对应的_func方法,将数据发送至Server端。
Client端就这样搞定了,接着来实现Server端,不用紧张,非常简单。
Server端的使用方式如下。
# server.py
import rpcserver
def add(a, b, c=10):
sum = a + b + c
return sum
s = rpcserver.RPCServer()
s.register_function(add) # 注册方法
s.loop(5000) # 传入要监听的端口
复制代码
实例化rpcserver.RPCServer类,然后通过register_function方法将想被Client端调用的方法传入,随后调用loop方法,将要监听的端口传入,RPCServer类的实现如下。
# rpcserver.py
class RPCServer(TCPServer, JSONRPC, RPCStub):
def __init__(self):
TCPServer.__init__(self)
JSONRPC.__init__(self)
RPCStub.__init__(self)
def loop(self, port):
# 循环监听 5000 端口
self.bind_listen(port)
print('Server listen 5000 ...')
while True:
self.accept_receive_close()
def on_msg(self, data):
return self.call_method(data)
复制代码
RPCServer继承自TCPServer、JSONRPC、RPCStub,这些类同样实现在rpcserver.py文件中并且给出了详细的注释,所以就详细解释了。
class TCPServer(object):
def __init__(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def bind_listen(self, port):
self.sock.bind(('0.0.0.0', port))
self.sock.listen(5)
def accept_receive_close(self):
'''获取Client端信息'''
(client_socket, address) = self.sock.accept()
msg = client_socket.recv(1024)
data = self.on_msg(msg)
client_socket.sendall(data) # 回传
client_socket.close()
class JSONRPC(object):
def __init__(self):
self.data = None
def from_data(self, data):
'''解析数据'''
self.data = json.loads(data.decode('utf-8'))
def call_method(self, data):
'''解析数据,调用对应的方法变将该方法执行结果返回'''
self.from_data(data)
method_name = self.data['method_name']
method_args = self.data['method_args']
method_kwargs = self.data['method_kwargs']
res = self.funs[method_name](*method_args, **method_kwargs)
data = {"res": res}
return json.dumps(data).encode('utf-8')
class RPCStub(object):
def __init__(self):
self.funs = {}
def register_function(self, function, name=None):
'''Server端方法注册,Client端只可调用被注册的方法'''
if name is None:
name = function.__name__
self.funs[name] = function
复制代码
至此,Client端和Server端都写好了,跑一下吧。
总结一下
通过上述代码,再次理解一下RPC中这几个重要的概念,理解的是不是深入了一下。
客户端(Client):服务调用方。
客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
服务端(Server):服务的真正提供者。
Network Service:底层传输,可以是 TCP 或 HTTP。
开源的RPC框架肯定不是这么简单的,其中考虑了特别的边界条件以及各种优化,但RPC本身确是简单的。
结尾
最近一直在研究Docker,尝试通过Go来写一个玩具docker,后面弄出来,会分享一下Go与docker相关的内容。
下篇文章见,对了,有帮助的话,点「在看」或「赞赏」进行催更吧。
python实现rpc框架_使用Python实现RPC框架相关推荐
- python 报表框架_自学Python还不晚!阿里达摩院推荐的Python学习教程,分享给大家...
在互联网信息爆炸的时代,我们经常面临各种与信息搜集有关的事情,但是信息来源网站多,信息量大,如果采用常规的人工搜索+office软件整理,往往要花费大量的时间. 这里为大家介绍一个门槛低.易上手的工具 ...
- python怎么更新数据库_在Python的Django框架中更新数据库数据的方法
先使用一些关键参数创建对象实例,如下: >>> p = Publisher(name='Apress', ... address='2855 Telegraph Ave.', ... ...
- python nameko用于生产_用 Python、 RabbitMQ 和 Nameko 实现微服务
"微服务是一股新浪潮" - 现如今,将项目拆分成多个独立的.可扩展的服务是保障代码演变的最好选择.在 Python 的世界里,有个叫做 "Nameko" 的框架 ...
- python新手练习项目_适合Python 新手的5大练手项目,你练了么?
已经学习了一段时间的Python,如果你看过之前W3Cschool的文章,就知道是时候该进去[项目]阶段了. 但是在练手项目的选择上,还存在疑问?不知道要从哪种项目先下手? W3Cschool首先有两 ...
- python configure函数 循环_使用python统计git仓库中频繁修改的热点函数
本篇博客以开源代码RT-Thread为例,描述了如何使用python扫描统计代码中频繁修改的函数,帮助我们发现系统中需求变化和BUG制造的重灾区. 需求背景 最近在学习设计模式时,印象深刻的一句话就是 ...
- python大数据免费_用python做大数据
不学Python迟早会被淘汰?Python真有这么好的前景? 最近几年Python编程语言在国内引起不小的轰动,有超越Java之势,本来在美国这个编程语言就是最火的,应用的非常非常的广泛,而Pytho ...
- python代码设计测试用例_(appium+python)UI自动化_08_unittest编写测试用例
前言 unittest是python自带的单元测试框架,类似于Junit(Java单元测试框架).支持自动化测试,可编写测试前置&后置条件,并且可批量运行测试用例并生成测试报告. 使用unit ...
- python大牛 关东升_《Python从小白到大牛》第4章 Python语法基础
本章主要为大家介绍Python的一些语法,其中包括标识符.关键字.常量.变量.表达式.语句.注释.模块和包等内容. 标识符和关键字 任何一种计算机语言都离不开标识符和关键字,因此下面将详细介绍Pyth ...
- python要学哪些_学python都要学哪些内容?
如果培训都是分五个阶段,第一阶段学习Python核心编程,主要是Python语言基础.Linux.MySQL,前期学习Python编程语言基础内容;中期主要涉及OOP基础知识,学习后应该能自己处理OO ...
最新文章
- IntelliJ IDEA 更新后,电脑卡成球,该如何优化?
- 陈键飞:基于随机量化的高效神经网络训练理论及算法
- php 折叠菜单,SlashdotMenu 折叠菜单
- [MySQL FAQ]系列 — 线上环境到底要不要开启query cache
- phpcms_v9推送到其他栏目后再在其他栏目删除导致数据库出错
- 阿里巴巴发布智能运维故障管理AI+生态计划
- pytorch torchvision类
- 面向对象闲话(一)——什么是对象
- Java运算符和类型转换
- python整数类型没有取值范围限制_python综述(一),复习
- 惠普计算机开机半花屏,惠普电脑花屏怎么办
- 七夕祝福网页制作_七夕福利 | 程序员土味情话大PK,专属好礼等你拿
- 关于mac m1 安装安卓模拟器
- linux shell搜索某个字符串,然后在后面加上字符串?字符串后面插入字符串?sed字符串后面插入字符串?...
- 从技术债务的角度, 谈谈重构
- 新势力新名片-上海度普新能源通过ASPICE CL2评估!
- 应用宝shangjia安全评估报告_《安全评估报告》提交指引
- User Agreement(APP用户协议)
- Qt编写地图综合应用55-海量点位标注
- 美团即时零售的优势不止“快”
热门文章
- 剑指Offer - 面试题65. 不用加减乘除做加法(位运算,要看哦)
- mysq命令行导出sql_mysql 命令行导入导出 sql
- 公安计算机技能测试题库,2018公安文职考试题库:行政职业能力测验
- j2ee和mysql怎么连接_J2EE数据库连接不再烦恼
- 数据库练习(二)三个数据库根据指定id获取name和存储数据库名称
- 计算机考研英语什么时候考试,计算机考研:早期复习三大注意事项
- 拦截游戏窗口被移动_Ruined King官网版-拳头rpg Ruined King游戏最新版下载v1.0
- 别再双塔了!谷歌提出DSI索引,检索效果吊打双塔,零样本超BM25!
- 再论推荐特征与embedding生成
- 吴恩达:机器学习应以数据为中心