什么是 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:用于消息对象与消息对象之间的编码与解码
网友评论