本文介绍了正确使用Netty LengthFieldPrepender和LengthFieldBasedFrameDecoder的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an application using Netty 3.6.6.I use netty to send random packet data from a client to a server.

发件人使用以下管道:

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

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

I wrap my packet data with a ChannelBuffer and I want the handler to prepend 4 byte length so that receiver can know where a packet begins and ends.

接收方使用:

        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;
    }

一切似乎都按预期进行.发送方一个接一个地发送大小随机的ChannelBuffer,接收方以相同的顺序接收相同的ChannelBuffer

Everything seems to work as expected. Sender sends randomly sized ChannelBuffers one after another and the receiver receives the same ChannelBuffers in the same order

现在我的问题是:

1.当我向通道写入一个较大的ChannelBuffer时,它会分成多次写入例如,我在测试日志中看到了这一点

1.When I write a large ChannelBuffer to the channel, it is broken down into several writesFor example, I see this in the logs for my tests

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组成.

So lets assume I am sending two 1MiB buffers(bufferA and bufferB) and each write is roughly broken down into 8 writes - bufferA1, bufferA2, ... and bufferB1, bufferB2, ...If bufferA4 fails to write( due to too much load or receiver incorrectly spending too much time in the callback ), is the framing going to break? That is bufferA is incorrectly comprised of bufferA1, bufferA2, bufferA3, bufferA5, bufferA6, bufferA7, bufferA8, bufferB1 on the receiver side.

是否有保证不破坏帧.

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

2.Is always returning null in NettyReceiveHandler::decode the correct approach as I dont have any upstream handlers?

感谢您的帮助.

推荐答案

假设使用TCP连接,则不会丢失大量写入操作. Netty会将数据排队,直到可以写入为止. Netty可以通过引发 INTEREST_OPS来表明其写队列已满事件,但这不会阻止您排队更多数据.

Assuming a TCP connection then your large writes won't be dropped. Netty will queue the data until it can be written. Netty may signal that it's write queue is full by raising an INTEREST_OPS event but it won't stop you queuing more data.

我个人会对此有所不同.我不会扩展LengthFieldBasedFrameDecoder,而是创建带有2个处理程序的管道-标准LengthFieldBasedFrameDecoder和NettyReceiveHandler.然后,您要做的就是重写messageReceived并使用e.getMessage()(或您所谓的Message事件参数)调用侦听器.调用LengthFieldBasedFrameDecoder的解码方法不会造成混乱,也不必担心是否需要返回null.只需处理消息即可.

Personally I would handle this a bit differently. I wouldn't extend LengthFieldBasedFrameDecoder but instead create a pipeline with 2 handlers - a standard LengthFieldBasedFrameDecoder and a NettyReceiveHandler. Then all you have to do is override messageReceived and call your listener with e.getMessage() (or whatever you've called the Message event parameter). There's no messing around calling LengthFieldBasedFrameDecoder's decode method, or worrying about whether you need to return null. Just handle the message.

这篇关于正确使用Netty LengthFieldPrepender和LengthFieldBasedFrameDecoder的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-14 15:59