欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-22 09:33:16
本文需要一点python socket基础。回顾rpc 客户端(client):服务调用方。 客户端存根(client stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再...

本文需要一点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 rpc 框架