Hessian 协议解释与实战(二):长整型、二进制数据与 Null
前段时间,翻译了 Hessian 2.0 的序列化协议,发布在了 Hessian 2.0 序列化协议(中文版)。但是,其中有很多言语不详之处。所以,接下来会用几篇文章来详细解释并实践一下 Hessian 序列化协议,以求做到知其然知其所以然。目录如下:
Hessian 2.0 序列化协议(中文版) — Hessian 序列化协议的中文翻译版。根据后面的“协议解释与实战”系列文章,增加了协议内容错误提示。
Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。
Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和
null
等三种类型的数据的处理。Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。
Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。
Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。
Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。
Hessian、Msgpack 和 JSON 实例对比 — 用实例对比 JSON、Hessian 和 MessagePack 的区别。
Avro、ProtoBuf、Thrift 的模式演进之路 — 翻译的 Martin Kleppmann 的文章,重点对比了 Avro、ProtoBuf、Thrift 的序列化处理思路。
在上一篇文章 Hessian 协议解释与实战(一) 中研究了布尔型数据、日期类型、浮点类型数据、整数类型数据等四种数据类型的处理方式。接下来,我们再来介绍长整数类型数据、二进制数据和 null
的处理情况。
基础工具方法
基础工具方法就不再赘述,请直接参考 Hessian 协议解释与实战(一):布尔、日期、浮点数与整数:基础工具方法 中提到的几个方法。
长整数类型数据
在 Hessian 2.0 序列化协议(中文版):长整数类型数据 中对长整型类型的数据做了描述,处理思路与整型数据类型的处理非常类似。所以,对长整型数据的验证思路也与 Hessian 协议解释与实战(一):整数类型数据 类似,在分割点进行实验和验证。
/**
* @author D瓜哥 · https://www.diguage.com/
*/
@Test
public void testLong() throws Throwable {
// 演示各个“区间”的分界线
longTo(Long.MIN_VALUE);
// 上下之间的数字,前缀是 0x4C,与协议相吻合
longTo(((long) Integer.MIN_VALUE) - 1L);
longTo((long) Integer.MIN_VALUE);
// 上下之间的数字,前缀是 0x59,不是协议中所写的 0x4C。
longTo(-262145L);
longTo(-262144L);
// 上下之间的数字,前缀的取值范围是 0x38 ~ 0x3B
// 与之相对应的正数的前缀取值范围是 0x3C ~ 0x3F
// 与协议中所写的 0x38 ~ 0x3F 相吻合
longTo(-2049L);
longTo(-2048L);
// 上下之间的数字,前缀的取值范围是 0xF0 ~ 0xF7
// 与之相对应的正数的前缀取值范围是 0xF8 ~ 0xFF
// 与协议中所写的 0xF0 ~ 0xFF 相吻合
longTo(-9L);
longTo(-8L);
// 上下之间的数字,前缀的取值范围是 0xD8 ~ 0xEF
// 与协议中所写的 0xD8 ~ 0xEF 相吻合
longTo(15L);
longTo(16L);
// 上下之间的数字,前缀的取值范围是 0xF8 ~ 0xFF
// 与之相对应的负数的前缀取值范围是 0xF0 ~ 0xF7
// 与协议中所写的 0xF0 ~ 0xFF 相吻合
longTo(2047L);
longTo(2048L);
// 上下之间的数字,前缀的取值范围是 0x3C ~ 0x3F
// 与之相对应的负数的前缀取值范围是 0x38 ~ 0x3B
// 与协议中所写的 0x38 ~ 0x3F 相吻合
longTo(262143L);
longTo(262144L);
// 上下之间的数字,前缀是 0x59,不是协议中所写的 0x4C。
longTo((long) Integer.MAX_VALUE);
longTo(((long) Integer.MAX_VALUE) + 1L);
// 上下之间的数字,前缀是 0x4C,与协议相吻合
longTo(Long.MAX_VALUE);
}
/**
* @author D瓜哥 · https://www.diguage.com/
*/
public void longTo(long value) throws Throwable {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Hessian2Output out = getHessian2Output(bos);
out.writeLong(value);
out.close();
byte[] result = bos.toByteArray();
System.out.println("\n== long: " + value + " ==");
System.out.println("== long: " + getBinaryString(value) + " ==");
printBytes(result);
}
// -- 输出结果 ------------------------------------------------
== long: Long.MIN_VALUE ==
== long: -9223372036854775808 ==
== long: 10000000,00000000,00000000,00000000,
00000000,00000000,00000000,00000000 ==
76 0x4C 01001100 L
-128 0x80 10000000
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
== long: Integer.MIN_VALUE - 1L ==
== long: -2147483649 ==
== long: 11111111,11111111,11111111,11111111,
01111111,11111111,11111111,11111111 ==
76 0x4C 01001100 L
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
127 0x7F 01111111
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
== long: Integer.MIN_VALUE ==
== long: -2147483648 ==
== long: 11111111,11111111,11111111,11111111,
10000000,00000000,00000000,00000000 ==
89 0x59 01011001 Y
-128 0x80 10000000
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
== long: -262145 ==
== long: 11111111,11111111,11111111,11111111,
11111111,11111011,11111111,11111111 ==
89 0x59 01011001 Y
-1 0xFF 11111111
-5 0xFB 11111011
-1 0xFF 11111111
-1 0xFF 11111111
== long: -262144 ==
== long: 11111111,11111111,11111111,11111111,
11111111,11111100,00000000,00000000 ==
56 0x38 00111000 8
0 0x00 00000000
0 0x00 00000000
== long: -2049 ==
== long: 11111111,11111111,11111111,11111111,
11111111,11111111,11110111,11111111 ==
59 0x3B 00111011 ;
-9 0xF7 11110111
-1 0xFF 11111111
== long: -2048 ==
== long: 11111111,11111111,11111111,11111111,
11111111,11111111,11111000,00000000 ==
-16 0xF0 11110000
0 0x00 00000000
== long: -9 ==
== long: 11111111,11111111,11111111,11111111,
11111111,11111111,11111111,11110111 ==
-9 0xF7 11110111
-9 0xF7 11110111
== long: -8 ==
== long: 11111111,11111111,11111111,11111111,
11111111,11111111,11111111,11111000 ==
-40 0xD8 11011000
== long: 15 ==
== long: 00000000,00000000,00000000,00000000,
00000000,00000000,00000000,00001111 ==
-17 0xEF 11101111
== long: 16 ==
== long: 00000000,00000000,00000000,00000000,
00000000,00000000,00000000,00010000 ==
-8 0xF8 11111000
16 0x10 00010000
== long: 2047 ==
== long: 00000000,00000000,00000000,00000000,
00000000,00000000,00000111,11111111 ==
-1 0xFF 11111111
-1 0xFF 11111111
== long: 2048 ==
== long: 00000000,00000000,00000000,00000000,
00000000,00000000,00001000,00000000 ==
60 0x3C 00111100 <
8 0x08 00001000
0 0x00 00000000
== long: 262143 ==
== long: 00000000,00000000,00000000,00000000,
00000000,00000011,11111111,11111111 ==
63 0x3F 00111111 ?
-1 0xFF 11111111
-1 0xFF 11111111
== long: 262144 ==
== long: 00000000,00000000,00000000,00000000,
00000000,00000100,00000000,00000000 ==
89 0x59 01011001 Y
0 0x00 00000000
4 0x04 00000100
0 0x00 00000000
0 0x00 00000000
== long: Integer.MAX_VALUE ==
== long: 2147483647 ==
== long: 00000000,00000000,00000000,00000000,
01111111,11111111,11111111,11111111 ==
89 0x59 01011001 Y
127 0x7F 01111111
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
== long: Integer.MAX_VALUE + 1L ==
== long: 2147483648 ==
== long: 00000000,00000000,00000000,00000000,
10000000,00000000,00000000,00000000 ==
76 0x4C 01001100 L
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
-128 0x80 10000000
0 0x00 00000000
0 0x00 00000000
0 0x00 00000000
== long: Long.MAX_VALUE ==
== long: 9223372036854775807 ==
== long: 01111111,11111111,11111111,11111111,
11111111,11111111,11111111,11111111 ==
76 0x4C 01001100 L
127 0x7F 01111111
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
-1 0xFF 11111111
这里有几点需要特别说明:
首先,需要特别强调的一点,协议中有一处是错误的:五个字节表示的数字的前缀是
0x59
(Y
),而不是0x4C
(L
)。这里也可以从另外一个角度来看这个问题:九个字节表示数字的前缀是0x4C
(L
),如果五个字节的数字是正确的,则这两个冲突,哪该怎么区分这两种数字呢?对于
-8
~15
的数字,使用字节中的后六位来表示;在编码
-2048
~2047
时,使用两个字节表示。其中,后面的12
位用于表示数值。11110000
(0xF0
)00000000
(0x00
) 表示-2048
,之后就在后十二位上逐渐加1
,直到11111111
(0xFF
)11111111
(0xFF
) 表示2047
。在编码
-262144
~262143
时,使用三个字节表示。其中,后面的十九位用于表示数值。00111000
(0x38
)00000000
(0x00
)00000000
(0x00
) 表示-262144
,之后就在后十九位上逐渐加1
,直到00111111
(0x3F
)11111111
(0xFF
)11111111
(0xFF
) 表示262143
。对于
Integer.MIN_VALUE
~-2049
和2048
~Integer.MAX_VALUE
这两个区间的数字,则直接取数字对应的最后 32 位二进制,然后在前面加一个前缀0x59
来作为序列化的结果。除上述之外的所有数字,则都是将其二进制位,并且在前面加一个前缀
0x4C
(L
)来作为序列化结果。有一点需要说明一下:在处理长整数时,在程序中是按照区间范围来处理的,基本原则是用尽可能少的字节来完整表示数字。这样的话,在下一个更大范围的数字是要去除上一个区间能表示的数。这点对于整数和长整数的处理方式都是一样的。画了一个图来更详细说明情况。
二进制数据
在 Hessian 2.0 序列化协议(中文版):二进制数据 中对二进制数据的处理进行了描述。但是,有一些言语不详的地方,比如“二进制数据编码在 chunk 里面”,但是并没有知名块的长度等。
由于需要处理比较长行的字节数组,先把打印字节数组的工具办法做个改造:
/**
* 打印字节数组
*
* @author D瓜哥 · https://www.diguage.com/
*/
private void printBytes(byte[] result) {
if (Objects.isNull(result)) {
System.out.println(".... bytes is null ....");
return;
}
int byteChunk = 8 * 1024;
if (0 < result.length && byteChunk < result.length && result[0] == 'A') {
for (int i = 0; i < result.length; i += byteChunk) {
int min = Math.max(i - 1, 0);
int max = Math.min(i + 4, result.length);
System.out.println(".... " + min + " ~ " + max + " ....");
for (; min < max; min++) {
printByte(result[min]);
}
}
System.out.println("...... " + result.length);
} else {
int min = 0;
int max = 10;
System.out.println(".... " + min + " ~ " + max + " ....");
for (; min < result.length && min < max; min++) {
printByte(result[min]);
}
if (result.length > max) {
System.out.println("...... " + result.length);
}
}
}
由于协议中描述不详细,直接翻看 Hessian 的代码:
public final static int SIZE = 8 * 1024;
public static final int BC_BINARY_CHUNK = 'A'; // non-final chunk
public static final int BC_BINARY_DIRECT = 0x20; // 1-byte length binary
public static final int BINARY_DIRECT_MAX = 0x0f;
public static final int BC_BINARY_SHORT = 0x34; // 2-byte length binary
public static final int BINARY_SHORT_MAX = 0x3ff; // 0-1023 binary
public void writeBytes(byte []buffer, int offset, int length)
throws IOException
{
if (buffer == null) {
if (SIZE < _offset + 16)
flushBuffer();
_buffer[_offset++] = (byte) 'N';
}
else {
while (SIZE - _offset - 3 < length) {
int sublen = SIZE - _offset - 3;
if (sublen < 16) {
flushBuffer();
sublen = SIZE - _offset - 3;
if (length < sublen)
sublen = length;
}
_buffer[_offset++] = (byte) BC_BINARY_CHUNK;
_buffer[_offset++] = (byte) (sublen >> 8);
_buffer[_offset++] = (byte) sublen;
System.arraycopy(buffer, offset, _buffer, _offset, sublen);
_offset += sublen;
length -= sublen;
offset += sublen;
flushBuffer();
}
if (SIZE < _offset + 16)
flushBuffer();
if (length <= BINARY_DIRECT_MAX) {
_buffer[_offset++] = (byte) (BC_BINARY_DIRECT + length);
}
else if (length <= BINARY_SHORT_MAX) {
_buffer[_offset++] = (byte) (BC_BINARY_SHORT + (length >> 8));
_buffer[_offset++] = (byte) (length);
}
else {
_buffer[_offset++] = (byte) 'B';
_buffer[_offset++] = (byte) (length >> 8);
_buffer[_offset++] = (byte) (length);
}
System.arraycopy(buffer, offset, _buffer, _offset, length);
_offset += length;
}
}
查看代码,并且经过简单计算可以得出如下规则:
0
~15
之间,直接使用一个字符进行编码,编码范围:[0x20, 0x2F]
16
~255
之间,使用一个前缀标志符0x34
+ 两个字符进行编码256
~511
之间,使用一个前缀标志符0x35
+ 两个字符进行编码512
~767
之间,使用一个前缀标志符0x36
+ 两个字符进行编码768
~1023
之间,使用一个前缀标志符0x37
+ 两个字符进行编码1024
~8189
之间,使用一个前缀标志符0x42
(B
) + 两个字符进行编码8190
~8204
之间,先使用一个前缀标志符
0x41
(A
) + 两个字符进行编码前8 * 1024 - 3 = 8189
个字节再使用一个字符进行编码剩余字符,编码范围:
[0x20, 0x2F]
后续长度的字节数组,都是按照如此编码:
先截取
8189 * N
个字节,将其编码成N
个块;然后,将剩余字节根据前六条规则进行编码。
接下来,我们上代码验证一下:
/**
* 测试二进制数据进行 Hessian 序列化
*
* @author D瓜哥 · https://www.diguage.com/
*/
@Test
public void testBinary() throws Throwable {
bytesTo(new byte[]{});
// 0~15 之间,直接使用一个字符进行编码, 0x20~0x2F
bytesTo(getBytesByLength((byte) '@', 15));
bytesTo(getBytesByLength((byte) '@', 16));
// 16~255 之间,使用一个前缀标志符 0x34 + 两个字符进行编码
bytesTo(getBytesByLength((byte) '@', 255));
bytesTo(getBytesByLength((byte) '@', 256));
// 256~511 之间,使用一个前缀标志符 0x35 + 两个字符进行编码
bytesTo(getBytesByLength((byte) '@', 511));
bytesTo(getBytesByLength((byte) '@', 512));
// 512~767 之间,使用一个前缀标志符 0x36 + 两个字符进行编码
bytesTo(getBytesByLength((byte) '@', 767));
bytesTo(getBytesByLength((byte) '@', 768));
// 768~1023 之间,使用一个前缀标志符 0x37 + 两个字符进行编码
bytesTo(getBytesByLength((byte) '@', 1023));
bytesTo(getBytesByLength((byte) '@', 1024));
// 1024~8189 之间,使用一个前缀标志符 0x42(B) + 两个字符进行编码
bytesTo(getBytesByLength((byte) '@', 8 * 1024 - 3));
bytesTo(getBytesByLength((byte) '@', 8 * 1024 - 3 + 1));
// 8190~8204 之间,
// 先使用一个前缀标志符 0x41(A) + 两个字符进行编码前 8 * 1024 - 3 = 8189 个字节
// 再使用一个字符进行编码, 0x21~0x2F。
// 后续长度的字节数组,都是按照如此编码:
// 首先使用 0x41(A) + 两个字符进行编码前 N * 8189 个字节
// 然后,剩余编码按照 0 ~ 8189 个字节的编码规则进行编码。
bytesTo(getBytesByLength((byte) '@', 8 * 1024 - 3 + 15));
bytesTo(getBytesByLength((byte) '@', 8 * 1024 - 3 + 16));
// 8205~8445 之间,使用一个前缀标志符 0x34 + 一个字符进行编码
bytesTo(getBytesByLength((byte) '@', 8 * 1024 - 3 + 256));
bytesTo(getBytesByLength((byte) '@', 8 * 1024 - 3 + 512));
bytesTo(getBytesByLength((byte) '@', 8 * 1024 - 3 + 768));
bytesTo(getBytesByLength((byte) '@', 8 * 1024 - 3 + 1024));
bytesTo(getBytesByLength((byte) '@', (8 * 1024 - 3) * 2));
bytesTo(getBytesByLength((byte) '@', (8 * 1024 - 3) * 2 + 1));
}
/**
* 生成指定长度的字节数组
*
* @author D瓜哥 · https://www.diguage.com/
*/
private byte[] getBytesByLength(byte b, int len) {
byte[] result = new byte[len];
Arrays.fill(result, b);
return result;
}
/**
* 二进制数据序列化
*
* @author D瓜哥 · https://www.diguage.com/
*/
public void bytesTo(byte[] bytes) throws Throwable {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Hessian2Output out = getHessian2Output(bos);
out.writeBytes(bytes);
out.close();
byte[] result = bos.toByteArray();
System.out.println("\n== byte array: length=" + bytes.length + " ==");
printBytes(bytes);
System.out.println("== byte array: hessian result ==");
printBytes(result);
}
// -- 输出结果 ------------------------------------------------
== byte array: length=0 ==
.... 0 ~ 10 ....
== byte array: hessian result ==
.... 0 ~ 10 ....
32 0x20 00100000
== byte array: length=15 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 15
== byte array: hessian result ==
.... 0 ~ 10 ....
47 0x2F 00101111 /
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 16
== byte array: length=16 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 16
== byte array: hessian result ==
.... 0 ~ 10 ....
52 0x34 00110100 4
16 0x10 00010000
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 18
== byte array: length=255 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 255
== byte array: hessian result ==
.... 0 ~ 10 ....
52 0x34 00110100 4
-1 0xFF 11111111
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 257
== byte array: length=256 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 256
== byte array: hessian result ==
.... 0 ~ 10 ....
53 0x35 00110101 5
0 0x00 00000000
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 258
== byte array: length=511 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 511
== byte array: hessian result ==
.... 0 ~ 10 ....
53 0x35 00110101 5
-1 0xFF 11111111
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 513
== byte array: length=512 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 512
== byte array: hessian result ==
.... 0 ~ 10 ....
54 0x36 00110110 6
0 0x00 00000000
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 514
== byte array: length=767 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 767
== byte array: hessian result ==
.... 0 ~ 10 ....
54 0x36 00110110 6
-1 0xFF 11111111
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 769
== byte array: length=768 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 768
== byte array: hessian result ==
.... 0 ~ 10 ....
55 0x37 00110111 7
0 0x00 00000000
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 770
== byte array: length=1023 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 1023
== byte array: hessian result ==
.... 0 ~ 10 ....
55 0x37 00110111 7
-1 0xFF 11111111
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 1025
== byte array: length=1024 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 1024
== byte array: hessian result ==
.... 0 ~ 10 ....
66 0x42 01000010 B
4 0x04 00000100
0 0x00 00000000
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 1027
== byte array: length=8189 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8189
== byte array: hessian result ==
.... 0 ~ 10 ....
66 0x42 01000010 B
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8192
== byte array: length=8190 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8190
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8194 ....
64 0x40 01000000 @
33 0x21 00100001 !
64 0x40 01000000 @
...... 8194
== byte array: length=8204 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8204
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8196 ....
64 0x40 01000000 @
47 0x2F 00101111 /
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8208
== byte array: length=8205 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8205
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8196 ....
64 0x40 01000000 @
52 0x34 00110100 4
16 0x10 00010000
64 0x40 01000000 @
64 0x40 01000000 @
...... 8210
== byte array: length=8445 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8445
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8196 ....
64 0x40 01000000 @
53 0x35 00110101 5
0 0x00 00000000
64 0x40 01000000 @
64 0x40 01000000 @
...... 8450
== byte array: length=8701 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8701
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8196 ....
64 0x40 01000000 @
54 0x36 00110110 6
0 0x00 00000000
64 0x40 01000000 @
64 0x40 01000000 @
...... 8706
== byte array: length=8957 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 8957
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8196 ....
64 0x40 01000000 @
55 0x37 00110111 7
0 0x00 00000000
64 0x40 01000000 @
64 0x40 01000000 @
...... 8962
== byte array: length=9213 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 9213
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8196 ....
64 0x40 01000000 @
66 0x42 01000010 B
4 0x04 00000100
0 0x00 00000000
64 0x40 01000000 @
...... 9219
== byte array: length=16378 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 16378
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8196 ....
64 0x40 01000000 @
66 0x42 01000010 B
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
...... 16384
== byte array: length=16379 ==
.... 0 ~ 10 ....
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
64 0x40 01000000 @
...... 16379
== byte array: hessian result ==
.... 0 ~ 4 ....
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 8191 ~ 8196 ....
64 0x40 01000000 @
65 0x41 01000001 A
31 0x1F 00011111
-3 0xFD 11111101
64 0x40 01000000 @
.... 16383 ~ 16386 ....
64 0x40 01000000 @
33 0x21 00100001 !
64 0x40 01000000 @
...... 16386
日志输出与我们上面的描述基本吻合。根据我们的实验,协议中有两个地方存在错误:
“
x42
(B
)表示结尾 chunk”表述不正确!这个得看截取完前面的 chunk 之后,剩余的字符的个数。如果大于 1023 才会以x42
(B
)开头。“字节
x62
(b
)表示任何非结尾 chunk”的也不正确。根据实际测试来看,应该是0x41
(A
)。
null
关于 null
的处理,在 Hessian 2.0 序列化协议(中文版): null
中有相关说明。情况也比较简单,这里只是做个验证。
关于 null
值,只有三种可能:
字节数组:
null
字符串:
null
— 字符串相关处理,在 Hessian 协议解释与实战(三):字符串 中,做详细介绍。对象:
null
— 对象相关处理,在 Hessian 协议解释与实战(四):链表、Map与对象 中,做详细介绍。
直接上代码验证一下:
/**
* 测试 null 进行 Hessian 序列化
*
* @author D瓜哥 · https://www.diguage.com/
*/
@Test
public void testNull() throws Throwable {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Hessian2Output out = getHessian2Output(bos);
// 字符串: null
out.writeString(null);
// 字节数组: null
out.writeBytes(null);
// 对象: null
out.writeObject(null);
out.close();
byte[] result = bos.toByteArray();
System.out.println("\n== null ==");
printBytes(result);
}
// -- 输出结果 ------------------------------------------------
== null ==
.... 0 ~ 10 ....
78 0x4E 01001110 N
78 0x4E 01001110 N
78 0x4E 01001110 N
可以看出,无论是什么类型的 null
值,序列化结果是一致的,都是 0x4E
(N
),与协议说明一直。
文章已经很长,就此打住。接下来,我们介绍关于字符串的处理: Hessian 协议解释与实战(三):字符串。