一個簡單RPC框架是如何煉成的(V)——引入傳輸層

開局篇我們說了,RPC框架的四個核心內容

  1. RPC數據的傳輸
  2. RPC消息 協議
  3. RPC服務註冊
  4. RPC消息處理   
接下來處理數據傳輸。實際應用場景一般都是基於socket。socket代碼比較多,使用起來也比較麻煩。而且具體的傳輸通道使用socket或者其他的方式,如更上層的http,或者android裏的binder,都是可替換的,只是具體的一種實現而已。所以,這裏我就偷個懶,只是引入一個很簡單的Connection類,用來描述一下如何將數據傳輸 這一層給獨立出來。

首先簡單列出Connection類的實現,很簡單,就是兩個list,一個管發送,一個管接收。(實現沒有考慮多線程安全,實際是必須考慮的)。
需要說明的是,這裏的recv的實現約定是阻塞式的,也就是如果沒有收到任何數據,recv調用會一直阻塞。
class Connection(object):
    '''
    @RPC 連接。一般說來,都是socket連接,這裏簡化起見,直接本地變量實現。
    '''


    def __init__(self, sending_msg_list, recving_msg_list):
        '''
        Constructor
        '''
        self.sending_msg_list = sending_msg_list
        self.recving_msg_list = recving_msg_list
    
    def send(self, message):
        self.sending_msg_list.append(message)
    
    def recv(self):
        while len(self.recving_msg_list) == 0: time.sleep(0.01)
        return self.recving_msg_list.pop(0)
    
    def isClosed(self):
        return False


有了這個connection,剩下的就只要將rpc消息統統通過這個connection去發送,通過這個Connection去接收。

接着修改客戶端的request請求,不再直接調用server端的procRequest方法,而是將請求交給connection,去發送。  然後等待connection收到server端的回覆,將回復消息從connection中取出來。
def request(self, req):
        # 全部簡化處理,不考慮線程安全問題,不考慮異步
        # 先是將RPC消息發送到服務端,然後服務端就會處理,並將結果發回到客戶端,客戶端這邊接收處理結果。
        # self.remote.procRequest(req) // 刪除
        self.conn.send(req)
        rsp = self.conn.recv()
        return rsp.result

同樣的,修改服務端收到request請求後的處理。首先反覆調用connection.recv()方法讀取客戶端發過來的請求。當請求處理完成後,不再直接以函數返回的方式return,而是將rsp交給connection,由connection負責傳輸給client
    # def procRequest(self, req): 調整參數列表,不再需要req
    def procRequest(self):
        # 循環讀取並處理收到的客戶端請求
        while True:
            req = self.conn.recv()
            rsp = Response()
            rsp.id = req.id   
            if req.command == 'sayHello':
                rsp.result = self.sayHello()
            elif req.command == 'whoAreYou':
                rsp.result = self.whoAreYou()
            else:
                raise Exception("unknown command")
            
            # return rsp  # rsp也是通過connection最終傳給client,而不是直接函數返回
            self.conn.send(rsp) 

最後,列一下connection的初始化
slist = []
    rlist = []
    client = Client(Connection(slist, rlist))
    server = Server(Connection(rlist, slist))
    server.start()


總結,引入傳輸層的意義在於
1. 實現client與server端的解耦,client端不再需要持有server端的對象了。 這也是實現“遠程調用 ”所必須的。
2. 傳輸層的實現有很大的自由度,一般說來,他無需關心具體的RPC消息的格式,只需要完成數據的可靠傳輸就可以了。
3. 傳輸層具體基於socket,binder, 是採用http,udp,tcp這些都是自由的,根據需要選擇就可以了。也就是相當於一個可以自由拼接的組件。
4. 上面的模型實在過於簡單,沒有考慮多線程保護,沒有考慮異常。實際比較理想的情況,應該起碼有個類,Connector,以及Channel。其中channel只負責數據的傳輸,Connector負責管理channel。
後續如果有時間,會再進行完善




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章