一個簡單RPC框架是如何煉成的(IV)——實現RPC訊息的編解碼
阿新 • • 發佈:2018-10-31
之前我們制定了一個很簡單的RPC訊息 的格式,但是還遺留了兩個問題,上一篇解決掉了一個,還留下一個
- 我們並沒有實現相應的encode和decode方法,沒有基於可以跨裝置的字串傳輸,而是直接的記憶體變數傳遞。
現在的RPC request不支援帶引數的請求命令。如add(a, b), 如何在RPC訊息中描述引數a,b 。
這裡我還是簡單原則,重點在於曉義嘛。利用python裡的兩個運算。 str 和eval。 假設 一個字典msg = { 'a' : 1, 'b' : 2}. 那麼str(msg) = " { 'a' : 1, 'b' : 2}", 注意變成字串嘍。 然後eval(" { 'a' : 1, 'b' : 2}")-->msg, 做一個eval運算,又從字串變成 字典變量了。 於是編碼時,先將RPC訊息轉換成dict,然後呼叫str編碼成字串。
設計已定,剩下的就只是code filling。 先修改一下原來Request的str方法,返回一個dict的字串表示。對Response也做類似處理
class Request(object): def __str__(self): return str({'id':self.id, 'command':self.command, 'parameter':self.parameter})
然後引入encode方法
@classmethod
def encode(cls, message):
if isinstance(message, Request):
return str(message)
elif isinstance(message, Response):
return str(message)
elif isinstance(message, Notification):
return str(message)
else:
raise Exception('unknown type when encode')
同樣的,引入decode方法,稍微複雜一些。主要的麻煩在於如何區分解碼出來的是Response還是Request 我的辦法是比較投機的,直接根據字典的內容去判斷。有command欄位的肯定是request,有result欄位的肯定是response
@classmethod
def decode(cls, data):
info = eval(data)
if 'command' in info:
request = Request()
request.id = info.get('id')
request.command = info.get('command')
request.parameter = info.get('parameter', {})
return request
elif 'result' in info:
response = Response()
response.id = info.get('id')
response.result = info.get('result')
return response
elif 'message' in info:
note = Notification()
note.message = info.get('message')
return note
else:
raise Exception('unknown data when decode')
另外,client和server的程式碼也要稍作調整,那個很簡單,呼叫一下上面的 方法就可以了,這裡不貼了。 over,RPC訊息 這一塊,我們徹底玩完了。 總結:
- Request和Resonse的定義可以一直不變,
- encode 和decode方法,如孫大聖,是可以千變萬化的。如果採用xml或者json或者其他的描述,只要自定義encode和decode方法即可
- 從更高的層次看,RPC訊息,其實就是對函式呼叫的一個描述,所以充其量就是view。既然是view,實際自由度是很大的。