1. 程式人生 > 其它 >Netty的自定義協議解碼器

Netty的自定義協議解碼器

做了使用一個接收stm32微控制器資料的專案,其中用到了netty自定義協議解碼器,在此記錄一下

  1. 自定義協議解碼器繼承ByteToMessageDecoder
  2. 當bytebuf不包含整個協議訊息長度時需要 return,直到bytebuf的長度包含整個協議的長度時,再進行解析
  3. stm32是小端資料,接收的時需要考慮大小端問題
  4. 當協議使用CRC32校驗時,需注意stm的CRC32和主流CRC32有所不同,而且還有注意資料大小端問題。具體參考這篇文章

PC端實現STM32硬體CRC32計算結果(基本原理)

下面是部分程式碼

public class MyProtocolByteDecoder extends ByteToMessageDecoder {

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().remoteAddress().toString());
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        Object decoded = this.decode(ctx, in);
        if (decoded != null && !decoded.equals("")) {
            out.add(decoded);
        }
    }

    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        //防止byteBuf過大,超過最大值時清理
        clearRead(in);
        //訊息小於接收的最小長度
        if (in.readableBytes() < 33) {
            return null;
        }
        //防止socket位元組流攻擊、客戶端傳來的資料過大,這裡需要對資料進行過濾掉
        if(in.readableBytes() >= 40960){
            in.skipBytes(in.readableBytes());
            return null;
        }
        //記錄訊息頭部位置
        int beginIndex;
        while (true) {
            beginIndex = in.readerIndex(); //記錄包頭開始位置
            //in.markReaderIndex(); //標記包頭開始index
            //讀取協議開始標誌  //讀取幀頭欄位 0-1
            short i = in.readShort();
            if((short)30959== i){
                break; //如果是開始標記,那麼就結束查詢
            }

            //如果讀完了所有的資料 都沒有獲取到 訊息頭部 則判定所有訊息為無效訊息,直接放棄掉
            if (in.readableBytes() == 0) {
                return null;
            }

        }
        //資料型別 2  可以接收兩種不同長度的資料
        byte type = in.readByte();
        int msgLength = 0;
        if (type ==1 ){
            msgLength = 3244;
        }else if (type ==2){
            msgLength = 28672;
        }
        //訊息長度 這裡已經讀了三個位元組所以要加3
        int i2 = in.readableBytes();
        if ( in.readableBytes()+3< msgLength) {
            //訊息長度不夠,還原readerIndex到訊息頭部的位置
            in.readerIndex(beginIndex);
            return null;
        }
    //下面就可以開始依據協議對資料進行解析了
   
}