Thrift的TCompactProtocol紧凑型二进制协议分析

Posted JavaGarden

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Thrift的TCompactProtocol紧凑型二进制协议分析相关的知识,希望对你有一定的参考价值。

Thrift的紧凑型传输协议分析:

用一张图说明一下Thrift的TCompactProtocol中各个数据类型是怎么表示的。

 

报文格式编码:

bool类型:

  一个字节。

  如果bool型的字段是结构体或消息的成员字段并且有编号,一个字节的高4位表示字段编号,低4位表示bool的值(0001:true, 0010:false),即:一个字节的低4位的值(true:1,false:2).

  如果bool型的字段单独存在,一个字节表示值,即:一个字节的值(true:1,false:2).

Byte类型:

  一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一个字节的值.

I16类型:

  一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一至三个字节的值.

I32类型:

  一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一至五个字节的值.

I64类型:

  一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一至十个字节的值.

double类型:

  一个字节的编号与类型组合(高4位编号偏移1,低4位类型),八个字节的值.

  注:把double类型的数据转成八字节保存,并用小端方式发送。

String类型:

  一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一至五个字节的负载数据的长度,负载数据.

Struct类型:

  一个字节的编号与类型组合(高4位编号偏移1,低4位类型),结构体负载数据,一个字节的结束标记.

MAP类型:

  一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一至五个字节的map元素的个数,一个字节的键值类型组合(高4位键类型,低4位值类型),Map负载数据.

Set类型:

  表示方式一:一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一个字节的元素个数和值类型组合(高4位键元素个数,低4位值类型),Set负载数据.

  适用于Set中元素个数小于等于14个的情况。

  表示方式二:一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一个字节的键值类型(高4位全为1,低4位值类型),一至五个字节的map元素的个数,Set负载数据.

  适用于Set中元素个数大于14个的情况。

List类型:

  表示方式一:一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一个字节的元素个数和值类型组合(高4位键元素个数,低4位值类型),List负载数据.

  适用于Set中元素个数小于等于14个的情况。

  表示方式二:一个字节的编号与类型组合(高4位编号偏移1,低4位类型),一个字节的键值类型(高4位全为1,低4位值类型),一至五个字节的map元素的个数,List负载数据.

  适用于Set中元素个数大于14个的情况。

消息(函数)类型:

  一个字节的版本,一个字节的消息调用(请求:0x21,响应:0x41,异常:0x61,oneway:0x81),一至五个字节的消息名称长度,消息名称,消息参数负载数据,一个字节的结束标记。

以上说明是基于相邻字段的编号小于等于15的情况。

如果字段相邻编号大于15,需要把类型和编号分开表示:用一个字节表示类型,一至五个字节表示编号偏移值。

 

阅读到这里,或许会疑问,为什么数值型的值用 “一至五个字节”表示?

原因:对数值进行压缩,压缩算法就是Varint,如下简单的说明一下什么是Varint数值压缩。

Varint数值压缩

一个整数一般是以32位来表示的,存储需要4个字节。

当如果整数大小在256以内,那么只需要用一个字节就可以存储这个整数,这样剩下的3个字节的存储空间空闲。

当如果整数大小在256到65536之间,那么只需要用两个字节就可以存储这个整数,这样剩下的2个字节的存储空间空闲。

当如果整数大小在65536到16777216之间,那么只需要用三个字节就可以存储这个整数,这样剩下的1个字节的存储空间空闲。

当如果整数大小在16777216到4294967296之间,那么需要用四个字节存储这个整数。

这时,Google引入了varint,把表示整数的空闲空间压缩,用这种思想来序列化整数。

这种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字,值越小的数字使用越少的字节数。

Varint将数按照7位分段,把一个整数压缩后存储。

Varint 中的每个字节的最高位 bit 有特殊的含义,如果该位为 1,表示后续的 byte 也是该数字的一部分,如果该位为 0,则结束。

其他的 7 个 bit 都用来表示数字。因此小于 128 的数字都可以用一个 byte 表示。大于 128 的数字,会用两个字节。

这样就可以实现数值压缩。

采用 Varint,对于很小的 int32 类型的数字,则可以用 1 个 byte 来表示。当然凡事都有好的也有不好的一面,采用 Varint 表示法,大的数字则需要 5 个 byte 来表示。

从统计的角度来说,一般不会所有的消息中的数字都是大数,因此大多数情况下,采用 Varint 后,可以用更少的字节数来表示数字信息。

实现Varint32代码:

1

以上是关于Thrift的TCompactProtocol紧凑型二进制协议分析的主要内容,如果未能解决你的问题,请参考以下文章

Thrift的TJsonProtocol协议分析

go thrift报错问题--WriteStructEnd

Schema 未完全从 Thrift 协议转换为 CQL 协议

HBase thrift/thrift2 使用指南

Thrift入门初探--thrift基础知识详解

Thrift写RPC接口

(c)2006-2024 SYSTEM All Rights Reserved IT常识