初识Netty原理(三)——解码和编码

在Netty底层读入的是ByteBuf二进制数据,在实际开发中,需要将它解码为Java的POJO对象,处理完业务后,需要将Java的POJO对象编码为ByteBuf二进制数据放进通道中进行传输。这里就需要使用到Netty的解码器和编码器。

Decoder原理和使用

原理

Netty中的解码器都直接或间接地实现了入站处理适配器,所以在使用时,直接继承解码器就行,而不需要再去实现处理适配器。
在继承解码器的时候需要重写decode方法(在父类中是个抽象方法),在decode方法里实现具体的解码过程。Netty中常用的三种解码器。

  • ByteToMessageDecoder:继承这个类,目的就是将ByteBuf二进制数据解码为Java POJO对象,decode的传入数据类型就是ByteBuf。
  • ReplayingDecoder:这个类是继承ByteToMessageDecoder的,它在内部将传入的ByteBuf换成了自己装饰的ReplayingDecoderBuffer(这个缓冲区可以实现在真正读取数据之前,先检查一下长度是否合格,如果合格再进行数据的读取,否则将抛出ReplayError给ReplayingDecoder(它在收到error后会保留当前数据)),可以免去读取时对长度的检查。这个类还有一个重要的属性state,它表示解码器在解码过程中的当前阶段(因为底层通信协议是分包传输的,为了数据的完整性,需要分阶段解码)。
  • MessageToMessageDecoder:继承这个类(继承时,需要指定入站的数据类型),是用于Java POJO对象之间的解码,比如将Integer解码为String等(这里的入站数据类型就是Integer)。

一般来说,在Netty中进行字符串的传输,采用简单的Header-Content内容传输协议:

  • 在协议的Head部分放置字符串的字节长度(还可以放置其它字段,如版本号、魔数等)。
  • 在协议的Content部分放置字符串的字节数组。

使用

下面来看一下示例吧(在代码中详细分析)。
先来看看ByteToMessageDecoder解码器,Log类见分析堆栈信息封装一个SLF4J的静态类

public class StringDecoder extends ByteToMessageDecoder {
   
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
   
        // 可读字节小于4,说明消息长度还没满,直接返回
        if (in.readableBytes() < 4){
   
            return;
        }
        // 设置回滚点
        in.markReaderIndex();
        // 读取前四个字节(消息头)存储的消息长度,同时会使readerIndex向前移动4个指针
        int len = in.readInt();
        Log.info("内容长度: [{}]", len);
        // 如果可读字节数小于消息长度,说明消息还不完整。
        if (in.readableBytes() < len){
   
            // 重置读指针,并返回
            in.resetReaderIndex();
            return;
        }
        byte[] inBytes = new byte[len];
        // 将ByteBuf中的数据读到字节数组中
        in.readBytes(inBytes, 0, len);
        // 将读出的字节数组编码成字符串加到结果列表中,向后传输
        out.add(new String(inBytes, StandardCharsets.UTF_8));
    }
}

一个简单的业务处理器,将解码的字符串打印出来。

public class StringProcessHandler extends ChannelInboundHandlerAdapter {
   
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   
        String s = (String)msg;
        Log.info("打印字符串:" + s);
    }
}

使用EmbeddedChannel来测试处理器。

public class TestDecoder {
   

    public static void main(String[] args){
   
        try{
   
            // 初始化一个通道初始化类
            ChannelInitializer channelInitializer = new ChannelInitializer<EmbeddedChannel>(){
   
                @Override
                protected void 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值