3

Hessian 协议解释与实战(一)

 2 years ago
source link: https://www.diguage.com/post/hessian-protocol-interpretation-and-practice-1/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Hessian 协议解释与实战(一)

2022-05-02

Hessian 协议解释与实战(一)

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

基础工具方法

Hessian 序列化之后的数据,都是字节数组,为了方便查看字节数组的二进制形式和十六进制形式,在正式开始之前,先介绍一下期间用到的辅助工具方法。闲言少叙,直接上代码:

布尔型数据

先来看一下布尔型数据的处理。布尔数据只有两种情况,在 Hessian 2.0 序列化协议(中文版):布尔型数据 中说明的很清楚。这里只是验证一下。

布尔型数据的处理比较简单明了,实验结果也与 Hessian 2.0 序列化协议(中文版):布尔型数据 中的描述非常吻合:字节 F 表示 false,字节 T 表示 true

接下来看一下日期类型的处理。在 Hessian 2.0 序列化协议(中文版):日期类型数据 中,只是是说明对日期类型分为两种情况处理,但是并没有说明区分标准。这里要重点探究一下区分标准。

这里有几点需要注意:

  1. Hessian2Output.writeUTCDate(time) 就可以看出,Hessian 是直接将日期转换成毫秒数来处理的,简单直接。

  2. 对于符合紧凑日期条件(毫秒数可以被 60000L 整除的数,即分钟以下的时间单位都为 0 的时间点。),直接将毫秒数除以 60000L 来表示其分钟数,这样只需要取最后 32 位的整数值即可。翻看 Hessian 的代码,也确实如此:

    Hessian 源代码
  3. 正常的日期格式,则是直接用毫秒数(长整型数字)的数值进行编码。

关于日期的处理,也和 Hessian 2.0 序列化协议(中文版):日期类型数据 相符。原协议也没什么歧义,这里就不再多做介绍。

浮点类型数据

接下来看一下浮点数的处理。在 Hessian 2.0 序列化协议(中文版):浮点类型数据 中,对浮点数的处理还有有不少言语不详的地方的,比如“32位浮点数等价的双精度浮点数”啥意思等。需要重点探索一下。

这里有几点说明一下:

  1. 协议中提到的 0.01.0 使用一个字节表示。

  2. 协议中提到的 -128.0 ~ 127.0 之间的“整数”浮点数,则是使用一个前缀 0x5D 和一个表示数字的字节来表示。

  3. 协议中提到的 -32768.0 ~ 32767.0 之间的“整数”浮点数,则是使用一个前缀 0x5E 和两个表示数字的字节来表示。

  4. 重点说明一下关于“32位浮点数等价的双精度浮点数,用四个字节来表示”。最初,D瓜哥 理解成 Float.MIN_VALUE ~ Float.MAX_VALUE 之间的数字可以用四个字节表示,但是测试一下发现是八个字节。后来,去翻了 Hessian 的源代码,才发现这个表述歧义非常大,更准确的表述应该是:假设 newValue = (int) x * 1000,如果 0.001 * newValue = x,则符合此条件,可以将整数 newValue 的二进制位作为 x 的序列化结果。换句话说,可以用 (Integer.MIN_VALUE ~ Integer.MAX_VALUE)/1000 表示的浮点数,才可以用四个字节表示。实验结果,也符合描述。相关代码如下:

    Hessian 源代码
  5. 除上述几种情况之外,其余都是使用九个字节来表示:一个标志位字节 0x44;八个按照 IEEE-754 浮点数标准 编码的浮点数字节。这里再多说一句:Hessian 在处理这种情况浮点数时,使用 java.lang.Double.doubleToRawLongBits(double value) 方法,将其二进制位转化成“相等”的 long 数,然后再将二进制位按照字节逐个添加到序列化结果中的。

  6. 综上所述, Hessian 2.0 序列化协议(中文版):浮点类型数据 的示例中提到的 12.25 按照九个字节也是一个错误示例。应该是按照五个字节编码。上面的程序运行的结果,也说明了D瓜哥的论断。

整数类型数据

Hessian 2.0 序列化协议(中文版):整数类型数据 中, 对于整数处理的说明已经比较清楚了。而且,相对来说,比较好解释:可以直接将其二进制表示打印出来和序列化的结果进行相互印证。

关于整数类型的处理,有几点做一下说明:

  1. 在编码 -16 ~ 47 时,用 100000000x80) 表示 -16,之后就在后六位上逐渐加 1,直到 101111110xBF) 来表示 47

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

    计算公式 value = ((code - 0xc8) << 8) + b0,还没搞清楚怎么计算。等搞清楚了,再来更新。能搞明白的小伙伴,欢迎留言交流。
  3. 在编码 -262144 ~ 262143 时,使用三个字节表示。其中,后面的十九位用于表示数值。110100000xD0000000000x00000000000x00) 表示 -262144,之后就在后十九位上逐渐加 1,直到 110101110xD7111111110xFF111111110xFF) 表示 262143

  4. 其余情况,则是按照五个字节来处理:一个标志位字节 0x49I)和四个 int 对应的二进制表示的字节。

为了更形象地说明问题,干脆画了个图来说明:

hessian int

文章已经很长,就此打住,剩下的一些数据类型后续在做说明。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK