netty LengthFieldBasedFrameDecoder

lvzhl 发布于 2016/12/07 21:47
阅读 456
收藏 0

最近在用netty处理tcp粘包时遇到一些问题,网关上传数据:[16 ,0 ,0 ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,12 ,0 ,0 ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16]  数据包前2个字节为长度字段[16,0],第3个字节为指令类型,第4个字节保留,之后是数据,我用的是ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 2, 4));但是结果没出来,不知道哪里出问题,请大神指教...如果是用1个字节代表长度字节就可以正确解决粘包问题,即ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(255, 0, 1,3, 4));输出如下两个数据包[ 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ], [ 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ], 但是实际情况是前2个字节为长度

加载中
0
悠久之风
悠久之风
前面两个字节表示长度[16, 0]换算成十进制是4096,测试的数据长度没有问题?把数据改为[0, 16, ...]试一试
0
lvzhl
lvzhl

4096不知道你是怎么算出来的,byte[]  bytes={16,0} 转成int之后就是16,byte[] bytes={0,1}转int是256,byte[] bytes={0,2}转int是512,byte[] bytes={1,1}转int是257,byte[] bytes={2,1}转int是257,...网关上传数据是byte[] bytes={16 ,0 ,0 ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,12 ,0 ,0 ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16},在client端代码:

public void channelActive(ChannelHandlerContext ctx){

    byte[] bytes={16 ,0 ,0 ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16 ,12 ,0 ,0 ,0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ,11 ,12 ,13 ,14 ,15 ,16}

    ctx.writeAndFlush(Unpooled.copiedBuffer(bytes))

}

如果没有加任何编解码器的话,server端是可以接收到上传过来的bytes,但是时候是存在粘包,server端代码:

public void channelRead(ChannelHandlerContext ctx, Object msg){

    ByteBuf buf = (ByteBuf) msg;

    byte[] bytes = new byte[buf.readableBytes()];

    buf.readBytes(bytes);


    for (byte b : bytes) {
        System.out.print(b+" ");
    }

    System.out.println(";");

}

控制台打印:

16 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 12 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16;

这里已经存在粘包,不是我想要的结果,如果在加上编解码器:

@Override
protected void initChannel(SocketChannel ch) throws Exception {
// TODO Auto-generated method stub

ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(255, 0, 1, 3, 4));


ch.pipeline().addLast(new NettyClientHandler());
}

控制台打印:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ;

1 2 3 4 5 6 7 8 9 10 11 12;

这才是我想要处理的逻辑,但实际上数据包的前两个字节是长度字段,这里却只用了一个字节长度字段 ,并不符合实际情况,如果用两个字节长度字段,也即ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535, 0, 2, 2, 4));却没有打印任何结果,这是为什么?是我参数给的不对吗?不管我参数怎么给,只要用了两个字节长度字段,都会出现问题...



0
lvzhl
lvzhl
调换之后行了,可是实际情况是第1个字节是低字节位,netty把它当成高字节了,如何把netty的逻辑改变,让第1 字节是低字节,第2字节是高字节?
0
KUANGJ
KUANGJ

LengthFieldBasedFrameDecoder 有构造方法可以指定长度字段的字节序。

public LengthFieldBasedFrameDecoder(
            ByteOrder byteOrder, int maxFrameLength, int lengthFieldOffset, int lengthFieldLength,
            int lengthAdjustment, int initialBytesToStrip, boolean failFast) {

0
lvzhl
lvzhl

此问题已经解决,同样感谢你的回复

返回顶部
顶部