1. 程式人生 > >netty中自定義協議(加碼器和解碼器)

netty中自定義協議(加碼器和解碼器)

1、什麼是粘包/拆包

       一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來處理資料,再加上網路上MTU的往往小於在應用處理的訊息資料,所以就會引發一次接收的資料無法滿足訊息的需要,導致粘包的存在。處理粘包的唯一方法就是制定應用層的資料通訊協議,通過協議來規範現有接收的資料是否滿足訊息資料的需要。

2、解決辦法

     2.1、訊息定長,報文大小固定長度,不夠空格補全,傳送和接收方遵循相同的約定,這樣即使粘包了通過接收方程式設計實現獲取定長報文也能區分。

     2.2、包尾新增特殊分隔符,例如每條報文結束都添加回車換行符(例如FTP協議)或者指定特殊字元作為報文分隔符,接收方通過特殊分隔符切分報文區分。

     2.3、將訊息分為訊息頭和訊息體,訊息頭中包含表示資訊的總長度(或者訊息體長度)的欄位

3、自定義協議,來實現TCP的粘包/拆包問題

      3.0  自定義協議,開始標記           

              

      3.1  自定義協議的介紹

             

      3.2  自定義協議的類的封裝

             

      3.3  自定義協議的編碼器

             

      3.4  自定義協議的解碼器

          

4、協議相關的實現

      4.1  協議的封裝

  1. import java.util.Arrays;  
  2. /** 
  3.  * <pre> 
  4.  * 自己定義的協議 
  5.  *  資料包格式 
  6.  * +——----——+——-----——+——----——+ 
  7.  * |協議開始標誌|  長度             |   資料       | 
  8.  * +——----——+——-----——+——----——+ 
  9.  * 1.協議開始標誌head_data,為int型別的資料,16進製表示為0X76 
  10.  * 2.傳輸資料的長度contentLength,int型別 
  11.  * 3.要傳輸的資料 
  12.  * </pre> 
  13.  */  
  14. public class SmartCarProtocol {  
  15.     /** 
  16.      * 訊息的開頭的資訊標誌 
  17.      */  
  18.     private int head_data = ConstantValue.HEAD_DATA;  
  19.     /** 
  20.      * 訊息的長度 
  21.      */  
  22.     private int contentLength;  
  23.     /** 
  24.      * 訊息的內容 
  25.      */  
  26.     private byte[] content;  
  27.     /** 
  28.      * 用於初始化,SmartCarProtocol 
  29.      *  
  30.      * @param contentLength 
  31.      *            協議裡面,訊息資料的長度 
  32.      * @param content 
  33.      *            協議裡面,訊息的資料 
  34.      */  
  35.     public SmartCarProtocol(int contentLength, byte[] content) {  
  36.         this.contentLength = contentLength;  
  37.         this.content = content;  
  38.     }  
  39.     public int getHead_data() {  
  40.         return head_data;  
  41.     }  
  42.     public int getContentLength() {  
  43.         return contentLength;  
  44.     }  
  45.     public void setContentLength(int contentLength) {  
  46.         this.contentLength = contentLength;  
  47.     }  
  48.     public byte[] getContent() {  
  49.         return content;  
  50.     }  
  51.     public void setContent(byte[] content) {  
  52.         this.content = content;  
  53.     }  
  54.     @Override  
  55.     public String toString() {  
  56.         return "SmartCarProtocol [head_data=" + head_data + ", contentLength="  
  57.                 + contentLength + ", content=" + Arrays.toString(content) + "]";  
  58.     }  
  59. }  

      4.2  協議的編碼器

  1. /** 
  2.  * <pre> 
  3.  * 自己定義的協議 
  4.  *  資料包格式 
  5.  * +——----——+——-----——+——----——+ 
  6.  * |協議開始標誌|  長度             |   資料       | 
  7.  * +——----——+——-----——+——----——+ 
  8.  * 1.協議開始標誌head_data,為int型別的資料,16進製表示為0X76 
  9.  * 2.傳輸資料的長度contentLength,int型別 
  10.  * 3.要傳輸的資料 
  11.  * </pre> 
  12.  */  
  13. public class SmartCarEncoder extends MessageToByteEncoder<SmartCarProtocol> {  
  14.     @Override  
  15.     protected void encode(ChannelHandlerContext tcx, SmartCarProtocol msg,  
  16.             ByteBuf out) throws Exception {  
  17.         // 寫入訊息SmartCar的具體內容  
  18.         // 1.寫入訊息的開頭的資訊標誌(int型別)  
  19.         out.writeInt(msg.getHead_data());  
  20.         // 2.寫入訊息的長度(int 型別)  
  21.         out.writeInt(msg.getContentLength());  
  22.         // 3.寫入訊息的內容(byte[]型別)  
  23.         out.writeBytes(msg.getContent());  
  24.     }  
  25. }  

      4.3  協議的解碼器

  1. import java.util.List;  
  2. import io.netty.buffer.ByteBuf;  
  3. import io.netty.channel.ChannelHandlerContext;  
  4. import io.netty.handler.codec.ByteToMessageDecoder;  
  5. /** 
  6.  * <pre> 
  7.  * 自己定義的協議 
  8.  *  資料包格式 
  9.  * +——----——+——-----——+——----——+ 
  10.  * |協議開始標誌|  長度             |   資料       | 
  11.  * +——----——+——-----——+——----——+ 
  12.  * 1.協議開始標誌head_data,為int型別的資料,16進製表示為0X76 
  13.  * 2.傳輸資料的長度contentLength,int型別 
  14.  * 3.要傳輸的資料,長度不應該超過2048,防止socket流的攻擊 
  15.  * </pre> 
  16.  */  
  17. public class SmartCarDecoder extends ByteToMessageDecoder {  
  18.     /** 
  19.      * <pre> 
  20.      * 協議開始的標準head_data,int型別,佔據4個位元組. 
  21.      * 表示資料的長度contentLength,int型別,佔據4個位元組. 
  22.      * </pre> 
  23.      */  
  24.     public final int BASE_LENGTH = 4 + 4;  
  25.     @Override  
  26.     protected void decode(ChannelHandlerContext ctx, ByteBuf buffer,  
  27.             List<Object> out) throws Exception {  
  28.         // 可讀長度必須大於基本長度  
  29.         if (buffer.readableBytes() >= BASE_LENGTH) {  
  30.             // 防止socket位元組流攻擊  
  31.             // 防止,客戶端傳來的資料過大  
  32.             // 因為,太大的資料,是不合理的  
  33.             if (buffer.readableBytes() > 2048) {  
  34.                 buffer.skipBytes(buffer.readableBytes());  
  35.             }  
  36.             // 記錄包頭開始的index  
  37.             int beginReader;  
  38.             while (true) {  
  39.                 // 獲取包頭開始的index  
  40.                 beginReader = buffer.readerIndex();  
  41.                 // 標記包頭開始的index  
  42.                 buffer.markReaderIndex();  
  43.                 // 讀到了協議的開始標誌,結束while迴圈  
  44.                 if (buffer.readInt() == ConstantValue.HEAD_DATA) {  
  45.                     break;  
  46.                 }  
  47.                 // 未讀到包頭,略過一個位元組  
  48.                 // 每次略過,一個位元組,去讀取,包頭資訊的開始標記  
  49.                 buffer.resetReaderIndex();  
  50.                 buffer.readByte();  
  51.                 // 當略過,一個位元組之後,  
  52.                 // 資料包的長度,又變得不滿足  
  53.                 // 此時,應該結束。等待後面的資料到達  
  54.                 if (buffer.readableBytes() < BASE_LENGTH) {  
  55.                     return;  
  56.                 }  
  57.             }  
  58.             // 訊息的長度  
  59.             int length = buffer.readInt();  
  60.             // 判斷請求資料包資料是否到齊  
  61.             if (buffer.readableBytes() < length) {  
  62. 相關推薦

    netty定義協議加碼解碼

    1、什麼是粘包/拆包        一般所謂的TCP粘包是在一次接收資料不能完全地體現一個完整的訊息資料。TCP通訊為何存在粘包呢?主要原因是TCP是以流的方式來處理資料,再加上網路上MTU的往往小於在應用處理的訊息資料,所以就會引發一次接收的資料無法滿足訊息的需要,導致粘包的存在。處理粘包的唯一方法就

    netty定義編碼解碼粘包處理

    這裡的實現方式是:將訊息分為兩部分,也就是訊息頭和訊息尾,訊息頭中寫入要傳送資料的總長度,通常是在訊息頭的第一個欄位使用int值來標識傳送資料的長度。 首先我們寫一個Encoder,我們繼承自Me

    淺析在QtWidget定義ModelbeginInsertRows()endInsertRows()是空架子,類似於一種信號,用來通知底層

    cti ron 初學者 開發 http 沒有 insert ati 學習 Qt 4推出了一組新的item view類,它們使用model/view結構來管理數據與表示層的關系。這種結構帶來的功能上的分離給了開發人員更大的彈性來定制數據項的表示,它也提供一個標準的model接

    Vue 定義元件包含例項

    Vue 支援自定義元件,方便我們在開發過程中根據自己的專案自定義元件。 定義 主要是通過 Vue.component( ) 來完成。新建一個 alert.js 檔案: // 自定義一個 alert 元件 Vue.component('alert', { template: '&

    Netty實現定義協議原始碼分析

    本篇 主要講的是自定義協議是如何實現的,以及自定義協議中會出現的問題和Netty是如何支援的。 分為4個部分 |– 粘包 拆包 資料包不全 和解決方案 |– 程式碼實現 |– ByteToMessageDecoder的原始碼分析 |– 過程流程圖 粘包

    vue定義元件外掛

    在vue專案中,可以自定義元件像vue-resource一樣使用Vue.use()方法來使用,具體實現方法: 1、首先建一個自定義元件的資料夾,比如叫loading,裡面有一個index.js,還有一個自定義元件loading.vue,在這個loading.v

    利用Netty構建定義協議的通訊

    在複雜的網路世界中,各種應用之間通訊需要依賴各種各樣的協議,比如:HTTP,Telnet,FTP,SMTP等等。在開發過程中,有時候我們需要構建一些適應自己業務的應用層協議,Netty作為一個非常優秀的網路通訊框架,可以幫助我們完成自定義協議的通訊。一般而言,我們制定的協議需要兩個部分:Header : 協議

    Android定義註解反射實現-執行時註解

    預備知識: Java註解基礎 Java反射原理 Java動態代理 一、佈局檔案的註解 我們在Android開發的時候,總是會寫到setContentView方法,為了避免每次都寫重複的程式碼,我們需要使用註解來代替我們做這個事情,只需要在類Activity上

    在Angular2使用SVG定義圖表條形圖、折線圖元件

    要求:使用者將資料作為引數傳進來,通過型別決定渲染何種型別的圖示。 demo: html: <ngo-chart [inputParams]="options"></ngo-ch

    儲存過程呼叫定義函式不在同一使用者下提示無許可權或識別符號無效

     問題描述:           在A使用者下自定了一個函式 : getName(); 然後在B使用者下建立儲存過程,呼叫了A使用者下的自定義函式getName;在編譯儲存過程時提示函式 getName無效。 解決方法:           將A使用者下自定義函式getNa

    Netty實現定義協議

           關於協議,使用最為廣泛的是HTTP協議,但是在

    定義監控網頁報警,郵件報警

    zabbix註:zabbix的安裝配置參考另一篇文章1.Zabbix客戶端配置[[email protected]/* */ ~]# cat /tmp/user.sh #!/bin/bashuptime |awk ‘{print $4}‘[[email protected]/* */

    js將一串隨機數字每四位加一個定義符號格式:1234-5678-90

    方法一:      let string = '1234567890',result = '', index = 0; for(let i=0; i<string.length; i++){      result +=

    定義Banner寫在Fragment裡了

    Fragment類裡新增 Banner package com.example.lenovo.myapplication.Fragment.Fragment; import android.content.Context; import android.os.Bundle; impor

    iOS定義tabbar沒有tabbar上的黑線

    自定義tabbar相信在很多專案中都要用到。有的時候 還需要那種 不規則的tabbar,例如中間高兩邊底,例如需要新增tabbar的背景圖片等等。這裡 我要介紹一種 自定義tabbar的方法 ,這種方法可以呼叫系統的 hidesBottomBarWhenPushed 方法,很方便的隱藏tab

    WPF TabIndex預設樣式修改:去掉預設虛線框、定義樣式Button控制元件為例

    去掉Tab選中預設虛線框 Tab鍵切換時,被選控制元件自動存在虛線框,有時候為了介面美觀,這個虛線框就顯得比較麻煩。廢話不多說,下面是方法。 <Window.Resources> <Style x:Key="MeyFocusVisual" TargetType="{

    Idea:通過Live Template定義模板類註釋、方法註釋

    1.選擇Live Template File-Settings--Editor--Live Template 2.建立自定義Template Group 點選右邊的+號,選擇Template Group,輸入名稱,比如user  

    ListView與定義介面卡顯示java端的資料

    一、自定義介面卡 1、BaseAdapter:是所有介面卡類的父類,可以對列表項進行最大限度的定製 2、自定義介面卡中的方法 @Override public int getCount() {//從java端獲取到多少條資料 return da

    android定義相機帶邊框按鈕

    前兩個月專案要求不能呼叫系統的相機,那就只能用自定義的了,查了一些資料,自己再研究了一下,自定義的相機還是有點複雜的,佈局和程式碼中都要用到一個重要的SurfaceView。 一、建立佈局,佈局的背景框可以讓美工給出,這裡姑且就是一個藍色的邊框,然後下面有三個按鈕,我里布局檔案activit

    SparkSQL 使用者定義函式UDF、UDAF、開窗

    UDF: 操作單個數據行,產生單個數據行; UDAF: 操作多個數據行,產生一個數據行。 UDTF: 操作一個數據行,產生多個數據行一個表作為輸出。 UDF函式 通過spark.udf.register(“funcName”, func) 來進行註冊 使用:se