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字节,如下所示:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0X00 | 0X0C | H | e | l | l | o | w | o | r | l | d | ! |
- 代码测试
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(大端)模式,字节序:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0X00 | 0X0C | H | e | l | l | o | w | o | r | l | d | ! |
LITTLE_ENDIAN(小端)模式,字节序:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0X0C | 0X00 | H | e | l | l | o | w | o | r | l | d | ! |
综上所述,两者区别就是报文头的字节顺序,通俗的说,大端模式可以理解为前置补零,小端模式理解为后置补零。