• 将字节解码为消息——ByteToMessageDecoder
  • 将一种消息类型解码为另一种——MessageToMessageDecoder

因为解码器是负责将入站数据从一种格式转换到另一种格式的,所以 Netty 的解码器实现了 ChannelInboundHandler
什么时候会用到解码器呢?很简单:每当需要为 ChannelPipeline 中的下一个ChannelInboundHandler 转换入站数据时会用到。此外,得益于 ChannelPipeline 的设计,可以将多个解码器链接在一起,以实现任意复杂的转换逻辑。

1.将字节解码为消息 ByteToMessageDecoder

将字节解码为消息(或者另一个字节序列)是一项如此常见的任务,以至于 Netty 为它提供了一个抽象的基类:ByteToMessageDecoder。由于你不可能知道远程节点是否会一次性 地发送一个完整的消息,所以这个类会对入站数据进行缓冲,直到它准备好处理。
它最重要方法

  1. protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;

这是你必须实现的唯一抽象方法。decode()方法被调用时将会传入一个包含了传入数据 的 ByteBuf,以及一个用来添加解码消息的 List。对这个方法的调用将会重复进行,直到确定没有新的元素被添加到该 List,或者该 ByteBuf 中没有更多可读取的字节时为止。然后, 如果该 List 不为空,那么它的内容将会被传递给 ChannelPipeline 中的下一个ChannelInboundHandler。

2.将一种消息类型解码为另一种 MessageToMessageDecoder

在两个消息格式之间进行转换(例如,从 String->Integer)
decode(ChannelHandlerContext ctx,I msg,List out)
对于每个需要被解码为另一种格式的入站消息来说,该方法都将会被调用。解码消息随后会被传递给 ChannelPipeline 中的下一个 ChannelInboundHandler。
MessageToMessageDecoder,T 代表源数据的类型

TooLongFrameException

由于 Netty 是一个异步框架,所以需要在字节可以解码之前在内存中缓冲它们。因此, 不能让解码器缓冲大量的数据以至于耗尽可用的内存。为了解除这个常见的顾虑,Netty 提供了 TooLongFrameException 类,其将由解码器在帧超出指定的大小限制时抛出。
为了避免这种情况,你可以设置一个最大字节数的阈值,如果超出该阈值,则会导致抛出一个 TooLongFrameException(随后会被 ChannelHandler.exceptionCaught()方法捕获)。然后,如何处理该异常则完全取决于该解码器的用户。某些协议(如 HTTP)可能允许你返回一个特殊的响应。而在其他的情况下,唯一的选择可能就是关闭对应的连接

  1. public class TooLongExSample extends ByteToMessageDecoder {
  2. private static final int MAX_SIZE = 1024;
  3. @Override
  4. protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
  5. throws Exception {
  6. int readable = in.readableBytes();
  7. if(readable>MAX_SIZE){
  8. ctx.close();
  9. throw new TooLongFrameException("传入的数据太多");
  10. }
  11. }
  12. }