Hessian 协议解释与实战(二):长整型、二进制数据与 Null

Hessian 协议解释与实战(二):长整型、二进制数据与 Null

前段时间,翻译了 Hessian 2.0 的序列化协议,发布在了 Hessian 2.0 序列化协议(中文版)。但是,其中有很多言语不详之处。所以,接下来会用几篇文章来详细解释并实践一下 Hessian 序列化协议,以求做到知其然知其所以然。目录如下:

  1. Hessian 2.0 序列化协议(中文版) — Hessian 序列化协议的中文翻译版。根据后面的“协议解释与实战”系列文章,增加了协议内容错误提示。

  2. Hessian 协议解释与实战(一):布尔、日期、浮点数与整数 — 介绍布尔型数据、日期类型、浮点类型数据和整数类型数据等四种类型的数据的处理。

  3. Hessian 协议解释与实战(二):长整型、二进制数据与 Null — 介绍长整数类型数据、二进制数据和 null 等三种类型的数据的处理。

  4. Hessian 协议解释与实战(三):字符串 — 专门介绍了关于字符串的处理。由于字符串需要铺垫的基础知识比较多,处理细节也有繁琐,所以单独成篇来介绍。

  5. Hessian 源码分析(Java) — 开始第四篇分析之前,先来介绍一下 Hessian 的源码实现。方便后续展开说明。

  6. Hessian 协议解释与实战(四):数组与集合 — 铺垫了一些关于实例对象的处理,重点介绍关于数组和集合的相关处理。

  7. Hessian 协议解释与实战(五):对象与映射 — 重点介绍关于对象与映射的相关处理。

  8. Hessian、Msgpack 和 JSON 实例对比 — 用实例对比 JSON、Hessian 和 MessagePack 的区别。

  9. 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

这里有几点需要特别说明:

  1. 首先,需要特别强调的一点,协议中有一处是错误的:五个字节表示的数字的前缀是 0x59Y),而不是 0x4CL)。这里也可以从另外一个角度来看这个问题:九个字节表示数字的前缀是 0x4CL),如果五个字节的数字是正确的,则这两个冲突,哪该怎么区分这两种数字呢?

  2. 对于 -8 ~ 15 的数字,使用字节中的后六位来表示;

  3. 在编码 -2048 ~ 2047 时,使用两个字节表示。其中,后面的 12 位用于表示数值。111100000xF0000000000x00) 表示 -2048,之后就在后十二位上逐渐加 1,直到 111111110xFF111111110xFF) 表示 2047

  4. 在编码 -262144 ~ 262143 时,使用三个字节表示。其中,后面的十九位用于表示数值。001110000x38000000000x00000000000x00) 表示 -262144,之后就在后十九位上逐渐加 1,直到 001111110x3F111111110xFF111111110xFF) 表示 262143

  5. 对于 Integer.MIN_VALUE ~ -20492048 ~ Integer.MAX_VALUE 这两个区间的数字,则直接取数字对应的最后 32 位二进制,然后在前面加一个前缀 0x59 来作为序列化的结果。

  6. 除上述之外的所有数字,则都是将其二进制位,并且在前面加一个前缀 0x4CL)来作为序列化结果。

  7. 有一点需要说明一下:在处理长整数时,在程序中是按照区间范围来处理的,基本原则是用尽可能少的字节来完整表示数字。这样的话,在下一个更大范围的数字是要去除上一个区间能表示的数。这点对于整数和长整数的处理方式都是一样的。画了一个图来更详细说明情况。

hessian long

二进制数据

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 的代码:

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;
  }
}

查看代码,并且经过简单计算可以得出如下规则:

  1. 0 ~ 15 之间,直接使用一个字符进行编码,编码范围: [0x20, 0x2F]

  2. 16 ~ 255 之间,使用一个前缀标志符 0x34 + 两个字符进行编码

  3. 256 ~ 511 之间,使用一个前缀标志符 0x35 + 两个字符进行编码

  4. 512 ~ 767 之间,使用一个前缀标志符 0x36 + 两个字符进行编码

  5. 768 ~ 1023 之间,使用一个前缀标志符 0x37 + 两个字符进行编码

  6. 1024 ~ 8189 之间,使用一个前缀标志符 0x42B) + 两个字符进行编码

  7. 8190 ~ 8204 之间,

    1. 先使用一个前缀标志符 0x41A) + 两个字符进行编码前 8 * 1024 - 3 = 8189 个字节

    2. 再使用一个字符进行编码剩余字符,编码范围: [0x20, 0x2F]

  8. 后续长度的字节数组,都是按照如此编码:

    1. 先截取 8189 * N 个字节,将其编码成 N 个块;

    2. 然后,将剩余字节根据前六条规则进行编码。

接下来,我们上代码验证一下:

/**
 * 测试二进制数据进行 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

日志输出与我们上面的描述基本吻合。根据我们的实验,协议中有两个地方存在错误:

  1. x42B)表示结尾 chunk”表述不正确!这个得看截取完前面的 chunk 之后,剩余的字符的个数。如果大于 1023 才会以 x42B)开头。

  2. “字节 x62b)表示任何非结尾 chunk”的也不正确。根据实际测试来看,应该是 0x41A)。

Hessian 字节(byte)数组的处理

null

关于 null 的处理,在 Hessian 2.0 序列化协议(中文版): null 中有相关说明。情况也比较简单,这里只是做个验证。

关于 null 值,只有三种可能:

  1. 字节数组: null

  2. 字符串: null — 字符串相关处理,在 Hessian 协议解释与实战(三):字符串 中,做详细介绍。

  3. 对象: 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 值,序列化结果是一致的,都是 0x4EN),与协议说明一直。

文章已经很长,就此打住。接下来,我们介绍关于字符串的处理: Hessian 协议解释与实战(三):字符串