Netty實現自定義通訊協議

概述

在網絡編程中,不管使用netty仍是其它的socket通信框架,都是經過TCP或UDP傳輸二進制流。發送方把要發送的對象轉化成二進制流發送出去;接收方把接收到的二進制流轉化爲對象進行處理。 爲了能讓接收方和發送方能對同一個二進制流有相同的認識,雙方必須提早約定好一個協議,即對象如何轉化爲二進制流,二進制流如何轉化爲對象,這樣通訊雙方纔不會產生誤解。java

自定義通訊協議

easy-im 項目中,定義以下通訊協議:git

魔數:4字節,通常爲固定值,本項目中使用0x88888888。通常咱們的應用於某個端口對外開放,爲了防止該端口被意外調用,咱們能夠在收到報文後,取前4個字節與魔數比對,若是不相同,則直接拒絕並關閉鏈接。

版本號: 1字節,通常是預留字段,爲了支持協議升級(這種狀況極少出現)。程序員

序列化算法:1字節,表示如何將java對象轉化爲二進制數據,以及如何反序列化。github

指令:1字節,表示該消息的意圖,如私聊、羣聊、登陸等。最多支持256種指令。web

數據長度:4字節,表示該字段後數據部分的長度。算法

數據:具體數據的內容。每種指令對應的數據是不一樣的。編程

序列化算法

本項目爲了簡單起見,使用json序列化算法。將Java對象轉換成json字符串,再轉化爲二進制數據,代碼以下: json

序列化器接口

Json序列化器
首先定義Serializer接口,serialize方法用於將對象序列化爲二進制數據,deSerialize方法用於將二進制反序列化成對象。getSerializerAlgorithm方法返回序列化算法。 JsonSerializer是Serializer的實現。

指令設計

定義Packet類,做爲全部指令的基類,其中getCommand方法爲抽象方法,需由子類實現,返回具體的指令類型。微信

登陸指令以下,登陸時須要發送userId,useName,password等信息,以及指令command:

指令類型以下:

編解碼實現

定義好序列化算法和指令以後,就能夠進行編解碼的實現了。編碼即將通訊包轉化爲二進制;解碼即將二進制轉化爲通訊包。websocket

編碼過程比較簡單,代碼以下,參照註釋便可明白,ByteBuf裏便是最後要發送的二進制數據:

這裏暫時跳過魔數和版本校驗,獲取到序列化算法、指令、數據長度和數據內容。根據指令咱們能夠知道請求類型是什麼(如登陸請求LoginRequestPacket、羣聊請求GroupChatRequestPacket),根據序列化算法,將數據內容反序列化成目標對象,解碼結束。

能夠看到,編碼與解碼是相反的過程。

總結

基於netty做爲網絡通訊基礎組件時,咱們必需要作以下幾個步驟:

  • 定義通信協議,通訊雙方需對此協議有一致的理解;
  • 編碼,將Java對象轉化爲二進制;
  • 解碼,將二進制轉化爲Java對象;
  • 業務處理

若是採用http、websocket等公有協議通訊,netty提供了許多類能夠實現步驟1,2,3,無需咱們編碼實現,只需調用相應的類和方法便可。

項目地址:github.com/sunnick/eas…

參考文檔: 《netty入門實戰:仿寫微信IM及時通信系統》

歡迎關注公衆號:程序員順仔

相關文章
相關標籤/搜索