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