概述:
在入站出站过程中,伴随着数据的解码和编码,解码器负责处理“入站数据”,编码器负责处理“出站数据”。
在入站处理过程中,需要将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的构造器,其源码如下:
![](https://img.haomeiwen.com/i19619362/7462108ae58bcc14.png)
参数说明如下:
- maxFrameLength
发送的数据包的最大长度。示例程序中该值为1024,表示一个数据包最多可发送1024个字节 - lengthFieldOffset
长度字段偏移量。指的是长度字段位于整个数据包内部的字节数组中的下标值 - lengthFieldLength
长度字段所占的字节数。如果长度字段是一个int整数,则为4,如果长度字段是一个short整数,则为2。 - lengthAdjustment
长度的矫正值 -
initialBytesToStrip
丢弃的起始字节数。在有效数据字段Content前面,还有一些其他字段的字节,作为最终的解析结果,可以丢弃。
代码运行结果如下:
代码运行结果
在Netty中,解码器有ByteToMessageDecoder和MessageToMessageDecoder两大基类。如果要从ByteBuf到POJO解码,则可继承ByteToMessageDecoder基类;如果要从某一种POJO到另一种POJO解码,则可继承MessageToMessageDecoder基类。
Netty Encoder
在Netty中的编码器有MessageToByteEncoder和MessageToMessageEncoder两大重要的基类。如果要从POJO到ByteBuf编码,则可继承MessageToByteEncoder基类;如果要从某一种POJO到另一种POJO编码,则可继承MessageToMessageEncoder基类
网友评论