这篇文章将为大家详细讲解有关用python实现RPC框架的方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

使用Python实现一个最简单的RPC框架,不具有实用意义,但可以让你清醒地理解RPC框架的几个组成部分,只是比看Python自带的xmlrpc清晰。

(推荐教程:Python入门教程)

本文需要一点Python socket基础。

回顾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.pyimportrpcclientc=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.pyclassRPCClient(TCPClient,RPCStub):pass

其中TCPClient负责通过Socket实现TCP链接并将数据请求过去,而RPCStub类主要将Client端调用Server端方法的相关信息打包,然后调用TCPClient类中的方法发送则可,两个类同样实现在rpclient.py文件中,代码如下。

classTCPClient(object):def__init__(self):self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)defconnect(self,host,port):'''链接Server端'''self.sock.connect((host,port))defsend(self,data):'''将数据发送到Server端'''self.sock.send(data)defrecv(self,length):'''接受Server端回传的数据'''returnself.sock.recv(length)classRPCStub(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)#接收方法执行后返回的结果returndatasetattr(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.pyimportrpcserverdefadd(a,b,c=10):sum=a+b+creturnsums=rpcserver.RPCServer()s.register_function(add)#注册方法s.loop(5000)#传入要监听的端口

实例化rpcserver.RPCServer类,然后通过register_function方法将想被Client端调用的方法传入,随后调用loop方法,将要监听的端口传入,RPCServer类的实现如下。

#rpcserver.pyclassRPCServer(TCPServer,JSONRPC,RPCStub):def__init__(self):TCPServer.__init__(self)JSONRPC.__init__(self)RPCStub.__init__(self)defloop(self,port):#循环监听5000端口self.bind_listen(port)print('Serverlisten5000...')whileTrue:self.accept_receive_close()defon_msg(self,data):returnself.call_method(data)

RPCServer继承自TCPServer、JSONRPC、RPCStub,这些类同样实现在rpcserver.py文件中并且给出了详细的注释,所以就详细解释了。

classTCPServer(object):def__init__(self):self.sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)defbind_listen(self,port):self.sock.bind(('0.0.0.0',port))self.sock.listen(5)defaccept_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()classJSONRPC(object):def__init__(self):self.data=Nonedeffrom_data(self,data):'''解析数据'''self.data=json.loads(data.decode('utf-8'))defcall_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}returnjson.dumps(data).encode('utf-8')classRPCStub(object):def__init__(self):self.funs={}defregister_function(self,function,name=None):'''Server端方法注册,Client端只可调用被注册的方法'''ifnameisNone:name=function.__name__self.funs[name]=function

至此,Client端和Server端都写好了。

测试:

关于用python实现RPC框架的方法就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。