Skip to content

tinybuf序列化协议

夏楚 edited this page Jul 6, 2021 · 3 revisions

1、设计目的

本文旨在设计一种轻量级的序列化协议,该协议能满足轻量可嵌入式移植序列化反序列高性能序列化后字节压缩度高等要求。

2、支持的数据类型

  • null:未定义和赋值的类型。

  • int:整数,可变长度整数,最大支持int64,整数又可以分成正整数负整数

  • bool:布尔型,布尔型分为真或假

  • double:双精度浮点型

  • string:字符串型,可以存放二进制数据

  • map:key-value字典数据类型

  • array:数组型

3、数据类型的定义

类型 类型枚举值 解释
null 0 空类型,未定义的类型
positive int 1 可变长度正整数
negtive int 2 可变长度负整数
bool true 3 布尔真
bool false 4 布尔假
double 5 双精度浮点型
string 6 UTF8字符串
map 7 字典
array 8 数组

4、各种数据类型的序列化

4.1、null

  • null类型固定为1个字节长度,类型值为0
  • 内存布局:
 0 1 2 3 4 5 6 7 
+---------------+
|               |               
|   0(null)     |  
|               |       
+---------------+

4.1、positive int

  • 可变长度正整数长度浮动不固定,采用 1 + N模式,第一个字节固定为1,表明为可变长度正整数。

  • 后续字节采用小端模式排列,低位字节在前,高位字节在后。

  • 每个字节的最高位bit表明有无后续字节,其余7bit表明有效长度。

  • 最大可表述64位有符号整数。

  • 内存布局:

0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0
+---------------+-+-------------+---------------+---------------+
|								|b|             |               |b|             |              
|1(positive int)|i|    length0  |      ....     |i|   lengthN   |  
|								|t|             |               |t|             | 
|								|0|             |               |N|             | 
+---------------+-+-------------+---------------+---------------+
  • 序列化算法:

    /**
     * 序列化整型
     * @param in 整型
     * @param out 序列化字节存放地址,最少预留10个字节
     * @return 序列化字节长度
     */
    static inline int int_serialize(uint64_t in, uint8_t *out){
        int index = 0;
        for(int i = 0; i <= (8 * sizeof(in)) / 7 ; ++i, ++index){
            //取最低位7bit
            out[index] = in & 0x7F;
            //右移7位
            in >>= 7;
            if(!in){
                //剩余字节为0,最高位bit为0,停止序列化
                break;
            }
            //后面还有字节,那么最高位bit为1
            out[index] |= 0x80;
        }
        //返回序列化后总字节数
        return ++index;
    }
  • 反序列化算法:

    /**
     * 反序列化整型
     * @param in 输入字节流
     * @param in_size 输入字节数
     * @param out 序列化后的整型
     * @return 代表反序列化消耗的字节数
     */
    static inline int int_deserialize(const uint8_t *in, int in_size, uint64_t *out){
        if(in_size < 1){
            return 0;
        }
        *out = 0;
        int index = 0;
        while (1){
            uint8_t byte = in[index];
            (*out) |= (byte & 0x7F) << ((index++) * 7);
            if((byte & 0x80) == 0){
                //最高位为0,所以没有更多后续字节
                break;
          }
            //后续还有字节
            if(index >= in_size){
                //字节不够,反序列失败
                return 0;
            }
            if(index * 7 > 56 ){
                //7bit 最多左移动56位,最大支持64位有符号整形
                return -1;
            }
        }
        //序列号成功
        return index;
    }

4.2、negtive int

  • 可变长度负整数长度浮动不固定,采用 1 + N模式,第一个字节固定为2,表明为可变长度负整数。

  • 负整数在序列化时,先翻转成正整数,然后按照正整数方式序列化

  • 内存布局:

0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0
+---------------+-+-------------+---------------+---------------+
|								|b|             |               |b|             |              
|2(negtive int) |i|    length0  |      ....     |i|   lengthN   |  
|								|t|             |               |t|             | 
|								|0|             |               |N|             | 
+---------------+-+-------------+---------------+---------------+

4.3、bool true

  • 布尔真类型固定为1个字节长度,类型值为3

  • 内存布局:

 0 1 2 3 4 5 6 7 
+---------------+
|               |               
| 3(bool true)  |  
|               |       
+---------------+

4.4、bool false

  • 布尔真类型固定为1个字节长度,类型值为4

  • 内存布局:

 0 1 2 3 4 5 6 7 
+---------------+
|               |               
| 4(bool false) |  
|               |       
+---------------+

4.5、double

  • 双精度浮点型长度固定为9个字节,第一个字节固定为5,其余字节为double值。

  • double值为8个字节,采用大端模式排列。

  • 内存布局:

     0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0
    +---------------+---------------+---------------+---------------+
    |								|								|								|								|             
    |		5(double)		|		double[7]		|		double[6]		|		double[5]	  |
    |								|								|								|								|
    +---------------+- - - - - - - -+- - - - - - - -+- - - - - - - -+
    |								|								|								|								|             
    |		double[4]		|		double[3]		|		double[2] 	|		double[1]		|
    |								|								|								|								|
    +- - - - - - - -+---------------+---------------+---------------+
    |								|								            
    |		double[0]		|								
    |								|								
    +---------------+
    
    

4.6、string

  • 字符串序列化后分成3部分。

  • 第一部分固定为6表明为字符串。

  • 第二部分为浮动长度的整数,表明字符串字节长度。

  • 第三部分是字符串内容,不固定长度。

  • 内存布局:

     0 1 2 3 4 5 6 7 
    +---------------+------------------------------------+---------------+
    |								|								                     |               |
    |		6(string)		|	string length(variable length int) |  string bytes |
    |								|								                     |               |
    +---------------+------------------------------------+---------------+
    
    

4.7、map

  • map序列化主要分成4部分。
  • 第一个字节固定为7,表明为map
  • 第二部分为浮动长度整数,表明map中key-value对个数。
  • 第三部分为key-value对,其中key固定为string类型,value可能是各种类型。
  • 内存布局:
 0 1 2 3 4 5 6 7 
+---------------+---------------------+----------+--------+-----+----------+---------+
|								|								      |          |        |     |          |         |
|		7(map)		  |	      map size  N   |   key0   | value0 | ... |  keyN-1  | valueN-1|
|								|(variable length int)| (string) |        |     | (string) |         |
+---------------+---------------------+----------+--------+-----+----------+---------+

4.8、array

  • array序列化主要分成3部分。
  • 第一个字节固定为8,表明为array
  • 第二部分为浮动长度整数,表明array中元素个数。
  • 第三部分为元素值,元素值可能是各种类型。
  • 内存布局:
 0 1 2 3 4 5 6 7 
+---------------+----------------------+---------+-----+--------+
|								|								       |         |     |        |
|		8(array)	  |	      array size  N  |  value0 | ... |valueN-1|
|								|	(variable length int)|         |     |        |
+---------------+----------------------+---------+-----+--------+