python实现一个简单RPC框架的示例


Posted in Python onOctober 28, 2020

本文需要一点Python socket基础。

回顾RPC

python实现一个简单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端都写好了。

测试:

python实现一个简单RPC框架的示例

以上就是python实现一个简单RPC框架的示例的详细内容,更多关于python 实现RPC框架的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Django的session中对于用户验证的支持
Jul 23 Python
Python的Flask框架中的Jinja2模板引擎学习教程
Jun 30 Python
浅谈利用numpy对矩阵进行归一化处理的方法
Jul 11 Python
详解python tkinter教程-事件绑定
Mar 28 Python
Python 闭包,函数分隔作用域,nonlocal声明非局部变量操作示例
Oct 14 Python
Python3 Click模块的使用方法详解
Feb 12 Python
Django+boostrap 美化admin后台的操作
Mar 11 Python
Jupyter打开图形界面并画出正弦函数图像实例
Apr 24 Python
Python xml、字典、json、类四种数据类型如何实现互相转换
May 27 Python
pytorch 中forward 的用法与解释说明
Feb 26 Python
Python3自带工具2to3.py 转换 Python2.x 代码到Python3的操作
Mar 03 Python
python+opencv实现视频抽帧示例代码
Jun 11 Python
pycharm永久激活超详细教程
Oct 29 #Python
linux mint中搜狗输入法导致pycharm卡死的问题
Oct 28 #Python
浅谈Python __init__.py的作用
Oct 28 #Python
详解Selenium-webdriver绕开反爬虫机制的4种方法
Oct 28 #Python
详解Python流程控制语句
Oct 28 #Python
详解selenium + chromedriver 被反爬的解决方法
Oct 28 #Python
手把手教你从PyCharm安装到激活(最新激活码),亲测有效可激活至2089年
Nov 25 #Python
You might like
PHP+JS无限级可伸缩菜单详解(简单易懂)
2007/01/02 PHP
php 修改zen-cart下单和付款流程以防止漏单
2010/03/08 PHP
php数组去重的函数代码
2013/02/03 PHP
在Debian系统下配置LNMP的教程
2015/07/09 PHP
laravel5.0在linux下解决.htaccess无效和去除index.php的问题
2019/10/16 PHP
Javascript中的Split使用方法与技巧
2007/03/09 Javascript
JavaScript入门教程(12) js对象化编程
2009/01/31 Javascript
有趣的javascript数组定义方法
2010/09/10 Javascript
js 中{},[]中括号,大括号使用详解
2011/05/12 Javascript
js 连接数据库如何操作数据库中的数据
2012/11/23 Javascript
移动Web中图片自适应的两种JavaScript解决方法
2015/06/18 Javascript
jQuery地图map悬停显示省市代码分享
2015/08/20 Javascript
javascript实现列表切换效果
2016/05/02 Javascript
jQuery实现点击按钮文字变成input框点击保存变成文字
2016/05/09 Javascript
javascript中获取class的简单实现
2016/07/12 Javascript
JS编写函数实现对身份证号码最后一位的验证功能
2016/12/29 Javascript
web.js.字符串与正则表达式操作
2017/05/13 Javascript
微信小程序使用image组件显示图片的方法【附源码下载】
2017/12/08 Javascript
Vue2.0 http请求以及loading展示实例
2018/03/06 Javascript
AngularJS 多指令Scope问题的解决
2018/10/25 Javascript
微信小程序实现获取准确的腾讯定位地址功能示例
2019/03/27 Javascript
Vue Object 的变化侦测实现代码
2020/04/15 Javascript
[02:44]DOTA2英雄基础教程 钢背兽
2013/12/19 DOTA
[49:15]DOTA2-DPC中国联赛 正赛 CDEC vs XG BO3 第二场 1月19日
2021/03/11 DOTA
Django Admin中增加导出CSV功能过程解析
2019/09/04 Python
Python基础之函数原理与应用实例详解
2020/01/03 Python
Python pysnmp使用方法及代码实例
2020/08/24 Python
MADE法国:提供原创设计师家具
2018/09/18 全球购物
工程师自我评价怎么写
2013/09/19 职场文书
双十佳事迹材料
2014/01/29 职场文书
旅游局领导班子“四风”问题对照检查材料思想汇报
2014/09/29 职场文书
邀请函怎么写
2015/01/30 职场文书
工程款申请报告
2015/05/15 职场文书
2015年食品安全宣传周活动总结
2015/07/09 职场文书
考试后的感想
2015/08/07 职场文书
python中urllib包的网络请求教程
2022/04/19 Python