处理ByteToMessageDecoder中的异常

时间:2014-02-20 13:57:12

标签: java exception netty

我写了一个Decoder,它扩展了ByteToMessageDecoder。基本上,我想做的只是抛出异常(我假设DecoderException),如果我收到了不期望的消息,停止解码消息并关闭连接。

当我抛出一个异常时,会在下面的处理程序中捕获它,它将只记录它并关闭连接。而且我可以看到它正在发生,但随后又出现了问题......

由于某种原因,我得到另一条消息(相同的消息),直接进入解码器,解码器尝试再次解码它,但从下一个readerIndex开始,再次获得意外消息并以同样的原因抛出异常。

为什么我在管道中得到另一条相同的消息,而连接是关闭的?

如何防止这种情况发生?

public class Decoder extends ByteToMessageDecoder
{
    private static Logger LOG = LoggerFactory.getLogger(Decoder.class);

    private Codec codec;
    private int contentSize = 0;

    /**
     * @see io.netty.handler.codec.ByteToMessageDecoder#decode(io.netty.channel.ChannelHandlerContext, io.netty.buffer.ByteBuf, java.util.List)
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception
    {
        if (!buffer.isReadable())
            return;

        // read header
        if (contentSize == 0) {
            int id = buffer.readInt();
            if (id == -1) {
                LOG.warn("Received null message");
                throw new DecoderException("Null message has been received.");
            }
            codec = CodecRegistry.getInstance().getCodec(id);
            if (codec == null) {
                LOG.error("No codec found for id: " + id);
                throw new DecoderException("No codec found for id: " + id);
            }
            contentSize = buffer.readInt();
        }

        if (buffer.readableBytes() < contentSize) {
            return;
        }

        // read content
        ByteBufInputStream bbis = new ByteBufInputStream(buffer);
        out.add(codec.decode(bbis));
        contentSize = 0;
    }
}

@Sharable
public class ClientHandler extends ChannelHandlerAdapter
{
    private static Logger LOG = LoggerFactory.getLogger(ClientHandler.class);

    /**
     * @see io.netty.channel.ChannelHandlerAdapter#channelRead(io.netty.channel.ChannelHandlerContext, java.lang.Object)
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
    {
        LOG.info("I got the message!!! -> " + msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
    {
        LOG.error("Unexpected exception from downstream." + cause);
        ctx.close();
    }
}

public class ClientInitializer extends ChannelInitializer<SocketChannel>
{
    /**
     * @see io.netty.channel.ChannelInitializer#initChannel(io.netty.channel.Channel)
     */
    @Override
    protected void initChannel(SocketChannel ch) throws Exception
    {
        ChannelPipeline pipeline = ch.pipeline();

        pipeline.addLast("decoder", new Decoder());
        pipeline.addLast("encoder", new Encoder());

        // and then business logic.
        pipeline.addLast("handler", new ClientHandler());
    }
}

服务器发送的消息只包含8个字节:

buffer.writeInt(-1);
buffer.writeInt(12345);

所以我希望DecoderException("Null message has been received.");

我在日志中看到的是:

INFO main Client - Starting Client..........
WARN nioEventLoopGroup-2-1 Decoder - Received null message
ERROR nioEventLoopGroup-2-1 ClientHandler - Unexpected exception from downstream.io.netty.handler.codec.DecoderException: org.jasypt.contrib.org.apache.commons.codec_1_3.DecoderException: Null message has been received.
INFO nioEventLoopGroup-2-1 Client - Disconnected from the server.
ERROR nioEventLoopGroup-2-1 Decoder - No codec found for id: 12345
ERROR nioEventLoopGroup-2-1 ClientHandler - Unexpected exception from downstream.io.netty.handler.codec.DecoderException: org.jasypt.contrib.org.apache.commons.codec_1_3.DecoderException: No codec found for id: 12345

1 个答案:

答案 0 :(得分:1)

在尝试解码标头之前,必须确保缓冲区的字节数超过8个字节。如果我是你,我会这样做:

    // read header
    if (contentSize == 0) {
        if (buffer.readableBytes() < 8) {
            return;
        }

        int id = buffer.readInt();
        ...