美文网首页
Java网络编程:Netty框架学习(四)---Decoder和

Java网络编程:Netty框架学习(四)---Decoder和

作者: singleZhang2010 | 来源:发表于2020-12-07 16:53 被阅读0次

概述:

在入站出站过程中,伴随着数据的解码和编码,解码器负责处理“入站数据”,编码器负责处理“出站数据”。
在入站处理过程中,需要将ByteBuf二进制类型,解码成Java POJO对象。这个解码过程,可以通过Netty的Decoder解码器去完成;
在出站处理过程中,业务处理后的结果(出站数据),需要从某个Java POJO对象,编码为最终的ByteBuf二进制数据,然后通过底层Java通道发送到对端。在编码过程中,需要用到Netty的Encoder编码器去完成数据的编码工作。

Netty中的几种常用 Decoder

  • LineBasedFrameDecoder(行分割数据包解码器,最基础的一种解码器)
  • FixedLengthFrameDecoder(固定长度数据包解码器)
  • DelimiterBasedFrameDecoder(自定义分隔符数据包解码器)
  • LengthFieldBasedFrameDecoder(自定义长度数据包解码器,最为复杂的一种解码器)

就以LengthFieldBasedFrameDecoder的使用demo来加深印象,创建NettyLengthBasedDecoderDemo.java

package com.zhxin.nettylab.decoder.chapter2;

import com.zhxin.nettylab.decoder.chapter1.StringProcessHandler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import org.junit.Test;

import java.nio.charset.StandardCharsets;

/**
 * @ClassName NettyLengthBasedDecoderDemo
 * @Description //LengthFieldBasedFrameDecoder 解码器使用Demo
 * @Author singleZhang
 * @Email 405780096@qq.com
 * @Date 2020/12/7 0007 下午 4:13
 **/
public class NettyLengthBasedDecoderDemo {
    private String s = "SingleZhang 学习Netty 笔记记录!";
    private final static int VERSION = 100;

    /**
     * LengthFieldBasedFrameDecoder DEMO1
     * */
    @Test
    public void testLineBasedFrameDecoder(){

        try{
            /*
             * 第1个参数maxFrameLength设置为1024,表示数据包的最大长度为1024。
             * 第2个参数lengthFieldOffset设置为0,表示长度字段的偏移量为0,也就是长度字段放在了最前面,处于数据包的起始位置。
             * 第3个参数lengthFieldLength设置为4,表示长度字段的长度为4个字节,即表示内容长度的值占用数据包的4个字节。
             * 第4个参数lengthAdjustment设置为0,长度调整值的计算公式为:内容字段偏移量-长度字段偏移量-长度字段的字节数,
             * 在上面示例程序中实际的值为:4-0-4 =0。
             * 第5个参数initialBytesToStrip为4,表示获取最终内容Content的字节数组时,抛弃最前面的4个字节的数据。
             */
            final LengthFieldBasedFrameDecoder spliter = new LengthFieldBasedFrameDecoder(1024,
                    0,4,0,4);
            /*
             * 第1个参数maxFrameLength可以为1024,表示数据包的最大长度为1024个字节。
             * 第2个参数lengthFieldOffset为0,表示长度字段处于数据包的起始位置。
             * 第3个参数lengthFieldLength实例中的值为4,表示长度字段的长度为4个字节。
             * 第4个参数lengthAdjustment为2,
             * 长度调整值的计算方法为:内容字段偏移量 -长度字段偏移量 - 长度字段的长度 = 6-0-4 = 2;
             * 即 lengthAdjustment就是夹在内容字段和长度字段中的部分——版本号的长度。
             * 第5个参数initialBytesToStrip为6,表示获取最终Content内容的字节数组时,抛弃最前面的6个字节数据。
             * 即,长度字段、版本字段的值被抛弃。
             */
            //final LengthFieldBasedFrameDecoder spliter = new LengthFieldBasedFrameDecoder(1024,0,4,2,6);
            /*
             * 第1个参数maxFrameLength可以设置为1024,表示数据包的最大长度为1024个字节。
             * 第2个参数lengthFieldOffset可以设置为2,表示长度字段处于版本号的后面。
             * 第3个参数lengthFieldLength可以设置为4,表示长度字段为4个字节。
             * 第4个参数lengthAdjustment可以设置为4,
             * 长度调整的计算方法为:内容字段偏移量 - 长度字段偏移量 - 长度字段的长度 = 10-2-4 = 4。
             * lengthAdjustment就是夹在内容字段和长度字段中的部分——版本字段的长度。
             * 第5个参数initialBytesToStrip可以设置为10,表示获取最终Content内容的字节数组时,抛弃最前面的10个字节数据。换句话说,长度字段、版本字段、魔数字段的值被抛弃。
             */
            //final LengthFieldBasedFrameDecoder spliter = new LengthFieldBasedFrameDecoder(1024,2,4,4,10);
            ChannelInitializer initializer = new ChannelInitializer<EmbeddedChannel>() {
                @Override
                protected void initChannel(EmbeddedChannel ch) throws Exception {

                    /*
                     * 添加流水线
                     * 先添加解码器
                     * 再添加业务流程处理器
                     * */
                    ch.pipeline().addLast(spliter);
                    ch.pipeline().addLast(new StringDecoder(StandardCharsets.UTF_8));
                    ch.pipeline().addLast(new StringProcessHandler());
                }
            };
            EmbeddedChannel channel = new EmbeddedChannel(initializer);
            for(int i =1;i<=100;i++){

                ByteBuf buffer = Unpooled.buffer();
                String sendStr = i+"次发送:"+s;
                byte[] bytes = sendStr.getBytes(StandardCharsets.UTF_8);
                buffer.writeInt(bytes.length);
                buffer.writeBytes(bytes);

                channel.writeInbound(buffer); // 往Channel 写入 Buffer数据
            }
            Thread.sleep(Integer.MAX_VALUE);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

以上代码中,使用了LengthFieldBasedFrameDecoder的构造器,其源码如下:


LengthFieldBasedFrameDecoder类源码

参数说明如下:

  1. maxFrameLength
    发送的数据包的最大长度。示例程序中该值为1024,表示一个数据包最多可发送1024个字节
  2. lengthFieldOffset
    长度字段偏移量。指的是长度字段位于整个数据包内部的字节数组中的下标值
  3. lengthFieldLength
    长度字段所占的字节数。如果长度字段是一个int整数,则为4,如果长度字段是一个short整数,则为2。
  4. lengthAdjustment
    长度的矫正值
  5. initialBytesToStrip
    丢弃的起始字节数。在有效数据字段Content前面,还有一些其他字段的字节,作为最终的解析结果,可以丢弃。
    代码运行结果如下:


    代码运行结果

在Netty中,解码器有ByteToMessageDecoder和MessageToMessageDecoder两大基类。如果要从ByteBuf到POJO解码,则可继承ByteToMessageDecoder基类;如果要从某一种POJO到另一种POJO解码,则可继承MessageToMessageDecoder基类。

Netty Encoder

在Netty中的编码器有MessageToByteEncoder和MessageToMessageEncoder两大重要的基类。如果要从POJO到ByteBuf编码,则可继承MessageToByteEncoder基类;如果要从某一种POJO到另一种POJO编码,则可继承MessageToMessageEncoder基类

相关文章

网友评论

      本文标题:Java网络编程:Netty框架学习(四)---Decoder和

      本文链接:https://www.haomeiwen.com/subject/ptgzwktx.html