什么是 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: 用于消息对象与消息对象之间的编码与解码
来源: http://www.jianshu.com/p/4eff8bd32971