1. 程式人生 > >一個簡單RPC框架是如何煉成的(IV)——實現RPC訊息的編解碼

一個簡單RPC框架是如何煉成的(IV)——實現RPC訊息的編解碼

之前我們制定了一個很簡單的RPC訊息 的格式,但是還遺留了兩個問題,上一篇解決掉了一個,還留下一個

  • 我們並沒有實現相應的encode和decode方法,沒有基於可以跨裝置的字串傳輸,而是直接的記憶體變數傳遞。
  • 現在的RPC request不支援帶引數的請求命令。如add(a, b), 如何在RPC訊息中描述引數a,b 。
下面我們處理掉這個編解碼問題。 實際的RPC應用基本都是跨機器連線,所以無法直接傳遞記憶體變數,也就是說還需要將訊息編碼成 諸如字串一類的可以跨裝置傳輸的內容。具體的RPC訊息的封裝協議很多,常見的是基於xml,json封裝的。但如果抽象一下,實際也就是一個編解碼,管你編碼成什麼內容呢,就是不編碼也可以。管他黑貓白貓,只要能傳過去,就是好貓。

這裡我還是簡單原則,重點在於曉義嘛。利用python裡的兩個運算。 str 和eval。 假設 一個字典msg =  { 'a' : 1, 'b' : 2}.  那麼str(msg) =   " { 'a' : 1, 'b' : 2}", 注意變成字串嘍。         然後eval(" { 'a' : 1, 'b' : 2}")-->msg, 做一個eval運算,又從字串變成 字典變量了。         於是編碼時,先將RPC訊息轉換成dict,然後呼叫str編碼成字串。
         解碼時,先呼叫eval 得到dict物件,然後再轉換為具體的RPC訊息物件
設計已定,剩下的就只是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,實際自由度是很大的。