【问题标题】:Buffer Returned from LengthFieldBasedFrameDecoder too small从 LengthFieldBasedFrameDecoder 返回的缓冲区太小
【发布时间】:2013-01-16 06:22:36
【问题描述】:

我目前正在评估 Netty 以处理 Java 客户端与 C++ 服务器集成的套接字通信。消息传递协议具有以下结构 -

  • (Type)(SubType)(Length)(MessageBody) 与大小
  • <...> - 长度包括标题。

按照 Netty api 的子类 LengthFieldBasedFrameDecoder 来接收一个有效的完整数据包,然后根据接收到的类型对每个数据包进行解码。来自我正在使用的文档 -

  • lengthFieldOffset = 8
  • lengthFieldLength = 4
  • lengthAdjustment = -12(= HDR1 + LEN 的长度,负数)
  • initialBytesToStrip = 0

它可以正常工作大约 5 分钟(我每 5 秒左右收到一条消息),然后解码事件包含一个比消息大小短得多的 ChannelBuffer。 (我在崩溃前多次收到此消息)。然后我显然在我的内部解码代码中得到了一个 BufferUnderflowException 。难道我做错了什么?使用 LengthFieldBasedFrameDecoder 时,是否应该保证消息的缓冲区大小正确?

LengthFieldBasedFrameDecoder 类 -

public class CisPacketDecoder extends LengthFieldBasedFrameDecoder
{
    public CisPacketDecoder(int maxFrameLength, int lengthFieldOffset,
            int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment,
                initialBytesToStrip);       
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf)
            throws Exception 
    {       
        CisMessage message = null;      
        int type = buf.getInt(0); //Type is always first int
        CisMessageType messageType = CisMessageType.fromIntToType(type);
        if(messageType != null)
        {
            message = messageType.getObject();
            if(message != null)
            {
                message.decode(buf.toByteBuffer());
            }
            else
            {
                System.out.println("Unable to create message for type " + type);
            }
        }

        //mark the Channel buf as read by moving reader index
        buf.readerIndex(buf.capacity());
        return message;
    }

}

并在这里实例化。

public class PmcPipelineFactory implements ChannelPipelineFactory 
{

    @Override
    public ChannelPipeline getPipeline() throws Exception
    {
        ChannelPipeline pipeline = Channels.pipeline();

        pipeline.addLast("encoder", new CisPacketEncoder());
        pipeline.addLast("decoder", new CisPacketDecoder(1024, 8, 4, -12, 0));      
        pipeline.addLast("handler", new MsgClientHandler());
        return pipeline;
    }


} 

【问题讨论】:

    标签: netty


    【解决方案1】:

    您需要调用 super.decode(..) 并在您的 decode(..) 方法中对返回的 ChannelBuffer 进行操作。

    原来是这样的;

    public class CisPacketDecoder extends LengthFieldBasedFrameDecoder {
        public CisPacketDecoder(int maxFrameLength, int lengthFieldOffset,
                int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
            super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment,
                initialBytesToStrip);       
        }
    
        @Override
        protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buf)
            throws Exception {
    
            // THIS IS IMPORTANT!!!!!
            ChannelBuffer decoded = (ChannelBuffer) super.decode(ctx, channel, buf);
            if (decoded == null) {
                return null;
            }
    
            // NOW ONLY OPERATE ON decoded 
            CisMessage message = null;      
            int type = decoded.getInt(0); //Type is always first int
            CisMessageType messageType = CisMessageType.fromIntToType(type);
            if(messageType != null) {
                message = messageType.getObject();
                if(message != null) {
                    message.decode(decoded.toByteBuffer());
                } else {
                    System.out.println("Unable to create message for type " + type);
                }
            }
            return message;
        }
    }
    

    一定要检查大写 cmets。

    【讨论】:

    • 非常感谢,现在一切正常。不要以为我会自己找到那个!
    猜你喜欢
    • 1970-01-01
    • 2016-09-22
    • 1970-01-01
    • 1970-01-01
    • 2010-12-03
    • 2011-06-29
    • 1970-01-01
    • 1970-01-01
    • 2013-01-13
    相关资源
    最近更新 更多