当缓冲区大小小于帧大小时,LengthFieldBasedFrameDecoder无法正确解析 [英] LengthFieldBasedFrameDecoder not parsing correctly when buffer size is less than frame size

查看:370
本文介绍了当缓冲区大小小于帧大小时,LengthFieldBasedFrameDecoder无法正确解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用基于帧的解码器对Netty管道进行单元测试.如果我使用的缓冲区大小小于最大帧的大小,则看起来帧是不正确的.我正在测试包含两个消息的文件.长度字段是第二个作品,包括整个消息的长度,包括长度字段和它之前的作品.

 new LengthFieldBasedFrameDecoder(65536, 4, 4, -8, 0)

我正在读取具有各种块大小的文件.第一条消息的大小为348个字节,第二个消息为456个字节.如果使用的块大小为512、3456或更大,则将读取两条消息并将其正确地构造到下一个处理程序,该处理程序出于诊断目的将接收到的缓冲区的内容作为十六进制字符串打印出来.如果使用较小的块大小,则会发生成帧错误.用于读取和写入文件的代码如下所示.

public class NCCTBinAToCSV {
    private static String inputFileName = "/tmp/combined.bin";
    private static final int BLOCKSIZE = 456;
    public static void main(String[] args) throws Exception {
        byte[] bytes = new byte[BLOCKSIZE];
        EmbeddedChannel channel = new EmbeddedChannel(
                new LengthFieldBasedFrameDecoder(65536, 4, 4, -8, 0),
                new NCCTMessageDecoder(),
                new StringOutputHandler());
        FileInputStream fis = new FileInputStream(new File(inputFileName));
        int bytesRead = 0;
        while ((bytesRead = fis.read(bytes)) != -1) {
            ByteBuf buf = Unpooled.wrappedBuffer(bytes, 0, bytesRead);
            channel.writeInbound(buf);
        }
        channel.flush();
    }
}

成功运行后输出的块大小为356个字节,如下所示(为简洁起见,消息主体被截短了

LOG:DEBUG 2017-04-24 04:19:24,675[main](netty.NCCTMessageDecoder) -  com.ticomgeo.mtr.ncct.netty.NCCTMessageDecoder.decode(NCCTMessageDecoder.java:21) ]received 348 bytes

Frame Start========================================

(byte) 0xbb,   (byte) 0x55,   (byte) 0x05,   (byte) 0x16,   
(byte) 0x00,   (byte) 0x00,   (byte) 0x01,   (byte) 0x5c,   
(byte) 0x01,   (byte) 0x01,   (byte) 0x02,   (byte) 0x02,   
(byte) 0x05,   (byte) 0x00,   (byte) 0x00,   (byte) 0x00,   
(byte) 0x50,   (byte) 0x3a,   (byte) 0xc9,   (byte) 0x17,

....   
Frame End========================================

Frame Start========================================

(byte) 0xbb,   (byte) 0x55,   (byte) 0x05,   (byte) 0x1c,   
(byte) 0x00,   (byte) 0x00,   (byte) 0x01,   (byte) 0xc8,   
(byte) 0x01,   (byte) 0x01,   (byte) 0x02,   (byte) 0x02,   
(byte) 0x05,   (byte) 0x00,   (byte) 0x00,   (byte) 0x00,   
(byte) 0x04,   (byte) 0x02,   (byte) 0x00,   (byte) 0x01,  

如果将块大小更改为256,则长度字段似乎读取了错误的字节.

Exception in thread "main" io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 65536: 4294967040 - discarded
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:499)
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477)
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403)

解决方案

TL; DR;造成您的问题的原因是,netty重用了传入的bytebuf,然后您覆盖了其中的内容.

LengthFieldBasedFrameDecoder是通过继承设计的,可以重新使用传入的ByteBuf,因为当对象可以重复使用时,它的引用计数为1,因此使对象通过垃圾回收进行衰变是没有用的.您正在更改传入的bytebuf的内部结构,并因此在运行中更改帧.您应该使用copiedBuffer,而不是使用将传入的变量作为存储的wrappedBuffer,因为它正确地复制了它的副本,所以LengthFieldBasedFrameDecoder的内部可以用它自由地做事.

I am unit testing a netty pipeline using the frame based decoder. It looks like the framing is incorrect if I use buffer size that is smaller that the largest frame. I am testing with a file that contains two messages. The length field is the second work and includes the length of the entire message including the length field and the work before it.

 new LengthFieldBasedFrameDecoder(65536, 4, 4, -8, 0)

I am reading a file with various block sizes. The size of the first message is 348 bytes, the second is 456 bytes. If block size of 512, 3456, or larger, is used both messages are read and correctly framed to the next handler which for diagnostic purposes will print out as a hexadecimal string the contents of the buffer it received. If a smaller block size is used framing errors occur. The code used to read and write the file is shown below.

public class NCCTBinAToCSV {
    private static String inputFileName = "/tmp/combined.bin";
    private static final int BLOCKSIZE = 456;
    public static void main(String[] args) throws Exception {
        byte[] bytes = new byte[BLOCKSIZE];
        EmbeddedChannel channel = new EmbeddedChannel(
                new LengthFieldBasedFrameDecoder(65536, 4, 4, -8, 0),
                new NCCTMessageDecoder(),
                new StringOutputHandler());
        FileInputStream fis = new FileInputStream(new File(inputFileName));
        int bytesRead = 0;
        while ((bytesRead = fis.read(bytes)) != -1) {
            ByteBuf buf = Unpooled.wrappedBuffer(bytes, 0, bytesRead);
            channel.writeInbound(buf);
        }
        channel.flush();
    }
}

Output from a successful run with block size of 356 bytes is show below (with the body of the messages truncated for brevity

LOG:DEBUG 2017-04-24 04:19:24,675[main](netty.NCCTMessageDecoder) -  com.ticomgeo.mtr.ncct.netty.NCCTMessageDecoder.decode(NCCTMessageDecoder.java:21) ]received 348 bytes

Frame Start========================================

(byte) 0xbb,   (byte) 0x55,   (byte) 0x05,   (byte) 0x16,   
(byte) 0x00,   (byte) 0x00,   (byte) 0x01,   (byte) 0x5c,   
(byte) 0x01,   (byte) 0x01,   (byte) 0x02,   (byte) 0x02,   
(byte) 0x05,   (byte) 0x00,   (byte) 0x00,   (byte) 0x00,   
(byte) 0x50,   (byte) 0x3a,   (byte) 0xc9,   (byte) 0x17,

....   
Frame End========================================

Frame Start========================================

(byte) 0xbb,   (byte) 0x55,   (byte) 0x05,   (byte) 0x1c,   
(byte) 0x00,   (byte) 0x00,   (byte) 0x01,   (byte) 0xc8,   
(byte) 0x01,   (byte) 0x01,   (byte) 0x02,   (byte) 0x02,   
(byte) 0x05,   (byte) 0x00,   (byte) 0x00,   (byte) 0x00,   
(byte) 0x04,   (byte) 0x02,   (byte) 0x00,   (byte) 0x01,  

If I change the block size to 256, the wrong bytes seem to be read as the length field.

Exception in thread "main" io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 65536: 4294967040 - discarded
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:499)
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477)
    at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403)

解决方案

TL;DR; Your problem is caused because netty reuses the passed in bytebuf, and then you are overwriting the contents.

LengthFieldBasedFrameDecoder is designed through inheritance to reuse the passed in ByteBuf, because it is useless to let the object decay through garbage collection when you can reuse it because its reference count is 1. The problem however comes from the fact that you are changing the internals of the passed in bytebuf, and therefore changing the frame on the fly. Instead of making a wrappedBuffer, that uses your passed in variable as storage, you should use copiedBuffer, because that one properly makes a copy of it, so the internals of LengthFieldBasedFrameDecoder can do freely things with it.

这篇关于当缓冲区大小小于帧大小时,LengthFieldBasedFrameDecoder无法正确解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆