Netty4(四):Codec 编码与解码

作者: 聪明的奇瑞 | 来源:发表于2018-03-28 11:02 被阅读138次

    什么是 Codec

    • 网络中都是以字节码的数据形式来传输数据的,编写一个网络应用程序需要实现某种 codec (编解码器),codec 的作用就是将原始字节数据与目标程序数据格式进行互转
    • 解码器负责处理“入站”数据,编码器负责处理“出站”数据
    • 一旦一个消息被编码或解码它自动被调用 ReferenceCountUtil.release(message) ,如果你稍后还需要用到这个引用而不是马上释放,你可以调用 ReferenceCountUtil.retain(message) 增加引用计数,防止消息被释放
    • Netty 中的解码器其实就是一个特殊的 ChannelHandler,它将数据格式转换后传递到 ChannelPipeline 中的下一个 ChannelHandler 进行处理

    Decoder(解码器)

    ByteToMessageDecoder

    • 用于将入站字节转为消息(或其他字节序列),你不能确定远端是否会一次发送完一个完整的“信息”,因此这个类会缓存入站的数据,直到准备好了用于处理
    • 下面代码:
      • 实现继承了 ByteToMessageDecode 用于将字节解码为消息
      • 检查可读的字节是否至少有4个 ( int 是4个字节长度)
      • 从入站 ByteBuf 读取 int , 添加到解码消息的 List 中
    public class ToIntegerDecoder extends ByteToMessageDecoder {  
    
        @Override
        public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
                throws Exception {
            if (in.readableBytes() >= 4) {  
                out.add(in.readInt());  
            }
        }
    }
    
    • 你会发现在实际的读操作(这里 readInt())之前,必须要验证输入的 ByteBuf 要有足够的数据,这非常的麻烦,接下来看看 ReplayingDecoder

    ReplayingDecoder

    • 使用 ReplayingDecoder 就无需自己检查缓冲区是否有足够的字节,若 ByteBuf 中有足够的字节,则会正常读取,否则会停止解码
    public class ToIntegerDecoder2 extends ReplayingDecoder<Void> {   
    
        @Override
        public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
                throws Exception {
            out.add(in.readInt());  
        }
    }
    

    MessageToMessageDecoder

    • 用于从一种消息解码为另外一种消息(如 POJO 到 POJO)
    • 下面代码中将 Integer 转换为 String
    public class IntegerToStringDecoder extends
            MessageToMessageDecoder<Integer> { 
    
        @Override
        public void decode(ChannelHandlerContext ctx, Integer msg, List<Object> out)
                throws Exception {
            out.add(String.valueOf(msg)); 
        }
    }
    

    解码时处理太大的帧

    • Netty 是异步框架需要缓冲区字节在内存中,直到你能够解码它们。因此,你不能让你的解码器缓存太多的数据以免耗尽可用内存
    • 为了解决问题 Netty 提供了一个 TooLongFrameException,通常由解码器在帧太长时抛出
    • 你可以在你的解码器里设置一个最大字节数阈值,如果超出将导致 TooLongFrameException 抛出(并由 ChannelHandler.exceptionCaught() 捕获),然后由用户决定如何处理它
    public class SafeByteToMessageDecoder extends ByteToMessageDecoder { 
        private static final int MAX_FRAME_SIZE = 1024;
    
        @Override
        public void decode(ChannelHandlerContext ctx, ByteBuf in,
                           List<Object> out) throws Exception {
            int readable = in.readableBytes();
            if (readable > MAX_FRAME_SIZE) { 
                in.skipBytes(readable);        
                throw new TooLongFrameException("Frame too big!");
            }
        }
    }
    

    Encoder(编码器)

    MessageToByteEncoder

    • MessageToByteEncoder 用于将出站消息编码为字节
    • 下面代码中,我们将 Short 编码成 ByteBuf
    public class ShortToByteEncoder extends MessageToByteEncoder<Short> {  
        @Override
        public void encode(ChannelHandlerContext ctx, Short msg, ByteBuf out) throws Exception {
            out.writeShort(msg);  
        }
    }
    

    MessageToMessageEncoder

    • MessageToMessageEncoder 可以将出站数据从一种消息编码成另一种消息
    public class IntegerToStringEncoder extends MessageToMessageEncoder<Integer> { 
        @Override
        public void encode(ChannelHandlerContext ctx, Integer msg, List<Object> out) throws Exception {
            out.add(String.valueOf(msg));  
        }
    }
    

    Decoder / Encoder

    • Netty 还提供了编码/解码的组合处理类:
      • ByteToMessageCodec:用于字节与消息对象相互之间的编码与解码
      • MessageToMessageCodec:用于消息对象与消息对象之间的编码与解码

    相关文章

      网友评论

        本文标题:Netty4(四):Codec 编码与解码

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