日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python实现rpc框架_使用Python实现RPC框架

發(fā)布時間:2024/7/19 python 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python实现rpc框架_使用Python实现RPC框架 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

本文將會使用Python實現(xiàn)一個最簡單的RPC框架,玩具向,不具有實用意義,但可以讓你清醒的理解RPC框架的幾個組成部分,只是比看Python自帶的xmlrpc清晰。

本文需要一點Python socket基礎。

如果你對Python Socket基礎方面的內容不是很熟悉,推薦閱讀Real Python的「Socket Programming in Python (Guide)」

吐槽一下VSCode,在開發(fā)一些比較復雜的Python項目時,VSCode的debug功能讓人感到蛋疼,詢問了Windows下使用VSCode的同事,都沒有這樣的問題,不清楚VSCode對Mac的支持是否存在問題,還只是我單純的不會用:(

本文代碼比較簡單,所以還是使用VSCode進行開發(fā)。那我們開始吧!

回顧RPC

客戶端(Client):服務調用方。

客戶端存根(Client Stub):存放服務端地址信息,將客戶端的請求參數(shù)數(shù)據(jù)信息打包成網(wǎng)絡消息,再通過網(wǎng)絡傳輸發(fā)送給服務端。

服務端存根(Server Stub):接收客戶端發(fā)送過來的請求消息并進行解包,然后再調用本地服務進行處理。

服務端(Server):服務的真正提供者。

Network Service:底層傳輸,可以是 TCP 或 HTTP。

實現(xiàn)jsonrpc

在實現(xiàn)前,簡單理一下整體思路。

1.Network Service 直接使用Python Socket相關的API實現(xiàn)

2.傳輸數(shù)據(jù)使用JSON,在Socket層會被壓成二進制,我們無需關心

模仿xmlrpc,Client與Server都采用Minix多繼承機制來實現(xiàn),每個類負責自身的事情,最終暴露出現(xiàn)的只有一個類中有限的方法。

先從Client端開始實現(xiàn)。

# 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方法,該方法的效果就是將傳入的數(shù)據(jù)進行累加并將累加的結果返回,最后將add方法返回的結果打印出了。

RPCClient類繼承于TCPClient類與RPCStub類。

# rpclient.py

class RPCClient(TCPClient, RPCStub):

pass

復制代碼

其中TCPClient負責通過Socket實現(xiàn)TCP鏈接并將數(shù)據(jù)請求過去,而RPCStub類主要將Client端調用Server端方法的相關信息打包,然后調用TCPClient類中的方法發(fā)送則可,兩個類同樣實現(xiàn)在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):

'''將數(shù)據(jù)發(fā)送到Server端'''

self.sock.send(data)

def recv(self, length):

'''接受Server端回傳的數(shù)據(jù)'''

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')) # 發(fā)送數(shù)據(jù)

data = self.recv(1024) # 接收方法執(zhí)行后返回的結果

return data

setattr(self, function, _func)

return _func

復制代碼

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

當我們在Client端調用res = c.add(1, 2, c=3)時,會執(zhí)行RPCStub中的__getattr__方法,該方法會將Client端調用的方法、參數(shù)等信息通過TCPServer類的send方法發(fā)送,發(fā)送數(shù)據(jù)進行了JSON格式化,方便Server端解碼,隨后便調用recv方法等待Server端相應的數(shù)據(jù)返回。

因為RPCClient類本身沒有add方法,為了讓用戶做到Client端直接調用Server端方法的形式,先利用__getattr__構建了_func方法,并將其通過setattr方法設置到RPCClient類中,此時該類就有Server端方法對應的映射了。

調用add方法,就調用了對應的_func方法,將數(shù)據(jù)發(fā)送至Server端。

Client端就這樣搞定了,接著來實現(xiàn)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) # 傳入要監(jiān)聽的端口

復制代碼

實例化rpcserver.RPCServer類,然后通過register_function方法將想被Client端調用的方法傳入,隨后調用loop方法,將要監(jiān)聽的端口傳入,RPCServer類的實現(xiàn)如下。

# rpcserver.py

class RPCServer(TCPServer, JSONRPC, RPCStub):

def __init__(self):

TCPServer.__init__(self)

JSONRPC.__init__(self)

RPCStub.__init__(self)

def loop(self, port):

# 循環(huán)監(jiān)聽 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,這些類同樣實現(xiàn)在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):

'''解析數(shù)據(jù)'''

self.data = json.loads(data.decode('utf-8'))

def call_method(self, data):

'''解析數(shù)據(jù),調用對應的方法變將該方法執(zhí)行結果返回'''

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):存放服務端地址信息,將客戶端的請求參數(shù)數(shù)據(jù)信息打包成網(wǎng)絡消息,再通過網(wǎng)絡傳輸發(fā)送給服務端。

服務端存根(Server Stub):接收客戶端發(fā)送過來的請求消息并進行解包,然后再調用本地服務進行處理。

服務端(Server):服務的真正提供者。

Network Service:底層傳輸,可以是 TCP 或 HTTP。

開源的RPC框架肯定不是這么簡單的,其中考慮了特別的邊界條件以及各種優(yōu)化,但RPC本身確是簡單的。

結尾

最近一直在研究Docker,嘗試通過Go來寫一個玩具docker,后面弄出來,會分享一下Go與docker相關的內容。

下篇文章見,對了,有幫助的話,點「在看」或「贊賞」進行催更吧。

總結

以上是生活随笔為你收集整理的python实现rpc框架_使用Python实现RPC框架的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。