1. 程式人生 > 程式設計 >python實現一個簡單RPC框架的示例

python實現一個簡單RPC框架的示例

本文需要一點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



importrpcclient



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

classRPCClient(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)#接收方法執行後返回的結果

returndata



setattr(self,function,_func)

return_func

TCPClient類就是常規的Socket API的操作,無需多言,主要看看RPCStub類。

當我們在Client端呼叫res = c.add(1,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



importrpcserver



defadd(a,b,c=10):

sum=a+b+c

returnsum



s=rpcserver.RPCServer()

s.register_function(add)#註冊方法

s.loop(5000)#傳入要監聽的埠

例項化rpcserver.RPCServer類,然後通過register_function方法將想被Client端呼叫的方法傳入,隨後呼叫loop方法,將要監聽的埠傳入,RPCServer類的實現如下。

#rpcserver.py



classRPCServer(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=None



deffrom_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,name=None):

'''Server端方法註冊,Client端只可呼叫被註冊的方法'''

ifnameisNone:

name=function.__name__

self.funs[name]=function

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

測試:

python實現一個簡單RPC框架的示例

以上就是python實現一個簡單RPC框架的示例的詳細內容,更多關於python 實現RPC框架的資料請關注我們其它相關文章!