Netty框架编程之字节序大小端问题研究

12 篇文章 1 订阅

1. 背景

netty提供的LengthFieldBasedFrameDecoder解码器中,有个获取报文头长度方法getUnadjustedFrameLength,该方法有个参数ByteOrder,用来指定字节序是BIG_ENDIAN还是LITTLE_ENDIAN。
BIG_ENDIAN:In this order, the bytes of a multibyte value are ordered from most significant to least significant
LITTLE_ENDIAN:In this order, the bytes of a multibyte value are ordered from least significant to most significant

2. 代码分析

  • 报文说明
    代码中使用“Hello world!”字符为例,该字符占用12字节,报文头占2字节,共14字节,如下所示:
012345678910111213
0X000X0CHelloworld!
  • 代码测试
import java.nio.ByteOrder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.DecoderException;

public class EndianTest {

	public static final Logger log = LoggerFactory.getLogger(EndianTest.class);
	
	public static void main(String[] args) {
		byte[] src = "Hello World!".getBytes();
		byte[] dst = new byte[14];
		// [1]. BIG_ENDIAN(大端)模式,报文头字节序列
		dst[0] = 0X00;
		dst[1] = 0X0C;
		// [2]. LITTLE_ENDIAN(小端)模式,报文头字节序列
//		dst[0] = 0X0C;
//		dst[1] = 0X00;
		
		for (int t=0; t<src.length; t++) {
			dst[t+2] = src[t];
		}
		
		ByteBuf byteBuf = Unpooled.copiedBuffer(dst);
		// [3]. 大端测试
		long n = getUnadjustedFrameLength(byteBuf, 0, 2, ByteOrder.BIG_ENDIAN);
		// [4]. 小端测试
		//long n = getUnadjustedFrameLength(byteBuf, 0, 2, ByteOrder.LITTLE_ENDIAN);
		
		log.info("数据包报头长度:[{}]", n);
	}
	
	// 取自 LengthFieldBasedFrameDecoder类
	public static long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
        buf = buf.order(order);
        long frameLength;
        switch (length) {
        case 1:
            frameLength = buf.getUnsignedByte(offset);
            break;
        case 2:
            frameLength = buf.getUnsignedShort(offset);
            break;
        case 3:
            frameLength = buf.getUnsignedMedium(offset);
            break;
        case 4:
            frameLength = buf.getUnsignedInt(offset);
            break;
        case 8:
            frameLength = buf.getLong(offset);
            break;
        default:
            throw new DecoderException(
                    "unsupported lengthFieldLength: " + 2 + " (expected: 1, 2, 3, 4, or 8)");
        }
        return frameLength;
    }
}

  • 测试结果

[1]-[3]组合测试结果正常,日志如下

09:22:26.448 [main] INFO EndianTest - 数据包报头长度:[12]

[1]-[4]组合测试结果有误,日志如下

09:20:05.287 [main] INFO EndianTest - 数据包报头长度:[3072]

[2]-[4]组合测试结果正常,日志如下

09:20:52.396 [main] INFO EndianTest - 数据包报头长度:[12]

[2]-[3]组合测试结果有误,日志如下

09:21:23.824 [main] INFO EndianTest - 数据包报头长度:[3072]

3. 结论

BIG_ENDIAN(大端)模式,字节序:

012345678910111213
0X000X0CHelloworld!

LITTLE_ENDIAN(小端)模式,字节序:

012345678910111213
0X0C0X00Helloworld!

综上所述,两者区别就是报文头的字节顺序,通俗的说,大端模式可以理解为前置补零,小端模式理解为后置补零。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jinwen5290

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值