Netty 二進制通信協議設計

Netty 二進制 通信 協議 設計  二進制通信協議

2015年在臺灣省九份鐵路,這是一條日本人修建的用來採礦用的鐵路,現在重新修建後作爲客運鐵路,一路上週圍全是原始森林,一路上零零散散的小鎮,很溫馨。

                                                                                             微信公衆號

                                                           王皓的GitHub:https://github.com/TenaciousDWang       

 

        今天開始寫Netty實戰部分仿微信寫IM即時通訊系統,後面一系列是我對這段時間學習閃電俠教程的心得和總結,同時也記錄和複習一下,部分圖片用Excel畫的,湊合看吧。

 

       這一篇主要來講IM的通信協議設計及編碼解碼的程序設計。上篇文章講了ByteBuf,也就是Netty的數據傳輸的容器,本質是一個二進制數據包。例如數據信息在客戶端通過我們自定義的通訊協議編碼爲二進制數據包,然後在網絡通過TCP/IP協議傳送,傳輸過程與我們的應用層無關,服務端端只需要用對應的通訊協議解碼成有效的信息即可。

 

       

       對於Java面向對象編程來說,這個信息就是一個Java對象,根據我們自定義的通訊協議編碼爲二進制數據包,通過公網傳輸,到達目的地端解碼還原爲Java對象進行後面的邏輯處理。

 

 

 

        接下來,我們來設計一個通信協議,首先我們定義一個魔數,這裏參照Java的字節碼文件,開頭爲cafe babe是Gosling定義的一個魔數,用來標誌這個文件是一個Java類文件,同樣我們仿照一下來定義我們數據包的標誌,這裏我們也使用四個字節來定義0x12345678。

 

        接下來一個字節爲版本號,通常情況下是預留字段,用於協議升級的時候用到,多數情況下用不到,預留即可。

 

        序列化算法,表示將Java對象與二進制數據互轉的方式,比如Java自帶的序列化,json等,我們後面只用一個json即可,平時一直再用阿里的fastjson,所以這裏的序列化方法與反序列化方法就直接使用toJSONBytes()與parseObject()。

 

        由於我們要做一個IM聊天功能,那麼這個功能就會包含很多指令,例如登陸,登出,發送信息,接收信息等,每一個指令對應我們的一種邏輯,這裏用一個字節來表示,可以表示256種指令。

 

        後面我們用4個字節來表示數據長度,最後是數據信息N個字節。基本上這一套協議對於服務端與客戶端之間通信完全夠用,屬於萬金油級別。

 

通信協議的實現

 

       首先抽象出一個Packet類,裏面定義版本與指令,所有指令數據包對象都要實現這個Packet類。

 

 

      我們以登陸爲例創建一個登陸指令數據包對象LoginRequestPacket,這裏不再羅列userId,userName,password這三個屬性的get與set方法。

 

       登陸的話我們簡單定義用戶ID,用戶名,密碼,實現getCommand方法,由於是登陸指令所以我們返回一個登陸指令常量。LOGIN_REQUEST作爲常量,我們來創建一個接口盛放指令常量。

 

 

序列化過程實現

 

        數據包對象實現好後,接下來,我們來定義序列化接口。

 

    

        定義一個獲取序列化標識的方法,序列化方式的標識我們參照指令常量也定義一個接口來盛放。再定義一個序列化方法和一個反序列化方法。

 

 

        然後來實現這個序列化接口,使用阿里的fastjson來序列化。實現上述三個方法,第一個方法返回序列化算法標識,第二個方法使用JSON.toJSONBytes(object)將對象轉化爲二進制數據包,

 

 

編碼過程實現

 

 

        像把大象放進冰箱一樣簡單,第一步創建一塊ByteBuf容器,第二步將需要傳輸的Java對象序列化爲二進制數據,第三部將數據根據我們之前設計的通信協議填充到到ByteBuf容器中,返回一個ByteBuf數據包。

 

解碼過程實現

 

        在PacketCodeC中創建構造器函數,用來初始化兩個容器,用來盛放不同數據包類型與不同序列化工具。

 

 

        定義兩個方法用於從容其中取出,序列化方式和指令數據包類型。

 

 

        接下來是解碼過程。

 

 

        解碼過程,首先驗證魔數,獲取序列化標識用於指定用什麼方式序列化,再獲取指令標識,用來獲取需要轉化爲什麼類型的Java對象,最後獲取數據長度,根據長度創建一個byte數據用來存儲從ByteBuf中獲取的數據。當獲得Java對象類型與二進制字節數據後,進行反序列化,返回一個Java對象用於後續邏輯處理。與編碼一樣,只不過反向過了一遍。

 

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