正确使用Netty LengthFieldPrepender和LengthFieldBasedFrameDecoder

时间:2013-07-05 12:57:29

标签: netty

我有一个使用Netty 3.6.6的应用程序。 我使用netty将随机数据包数据从客户端发送到服务器。

发件人使用此管道:

    bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            @Override
            public ChannelPipeline getPipeline() {
                return Channels.pipeline(
                        new LengthFieldPrepender(4) );
            }
    });

我使用ChannelBuffer包装我的数据包数据,我希望处理程序在前面加上4个字节,以便接收者可以知道数据包的开始和结束位置。

接收者使用:

        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
            public ChannelPipeline getPipeline() throws Exception {
                    return Channels.pipeline(
                            new NettyReceiveHandler(listener));
            }
        });


    public class NettyReceiveHandler extends LengthFieldBasedFrameDecoder {
        @Override
        protected Object decode(ChannelHandlerContext ctx, Channel channel,
                ChannelBuffer buffer) throws Exception {
            ChannelBuffer decodedBuffer = (ChannelBuffer) super.decode(ctx, channel, buffer);
            if(decodedBuffer == null)
            {
                return null; // not ready yet
            }
            listener.handleObject(decodedBuffer);   
            return null;    // no upstream
        }

        public NettyReceiveHandler(NettyRecvListener listener) {
            super(THREEMiB, 0, 4, 0, 4); 
            this.listener = listener;       
        }

        private static final Logger logger = Logger.getLogger(
                NettyReceiveHandler.class.getName());

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
            logger.severe("Unexpected exception from downstream." + e.getCause());
            e.getChannel().close();
        }

        private final NettyRecvListener listener;
        private static final int THREEMiB = 3*1024*1024;
    }

一切似乎都按预期工作。发送者一个接一个地发送随机大小的ChannelBuffers,接收者以相同的顺序接收相同的ChannelBuffers

现在我的问题是:

1.当我向通道写一个大的ChannelBuffer时,它被分解成几个写入 例如,我在日志中看到了我的测试

WARNING: The pipeline contains no upstream handlers; discarding: [id: 0xa1b55c95, /127.0.0.1:52359 => localhost/127.0.0.1:9991] WRITTEN_AMOUNT: 131071

所以我假设我发送两个1MiB缓冲区(bufferA和bufferB),每次写入大致分为8个写入 - bufferA1,bufferA2,...和bufferB1,bufferB2,... 如果bufferA4无法写入(由于负载太大或接收器错误地在回调中花费了太多时间),框架是否会破坏?那就是bufferA在接收端不正确地由bufferA1,bufferA2,bufferA3,bufferA5,bufferA6,bufferA7,bufferA8,bufferB1组成。

是否有任何关于不打破框架的保证。

2.我总是在NettyReceiveHandler :: decode中返回null,因为我没有任何上游处理程序吗?

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

假设有TCP连接,那么您的大写不会被删除。 Netty会将数据排队,直到可以写入。通过引发INTEREST_OPS事件,Netty可能会发出写入队列已满的信号,但它不会阻止您排队更多数据。

就我个人而言,我会稍微处理一下。我不会扩展LengthFieldBasedFrameDecoder,而是创建一个包含2个处理程序的管道 - 标准的LengthFieldBasedFrameDecoder和NettyReceiveHandler。然后,您所要做的就是覆盖messageReceived并使用e.getMessage()(或任何您称为Message事件参数)调用您的侦听器。调用LengthFieldBasedFrameDecoder的解码方法,或者担心是否需要返回null,并没有搞乱。只需处理消息。