zoukankan      html  css  js  c++  java
  • protobuf编码

    protobuf能够跨平台提供轻量的序列化和反序列化,得益于其平台无关的编码格式,本文就介绍下其中的编码格式。

    Varints

    在protobuf中大量使用到了Varints的编码格式,这是一个可变长度的编码格式用于编码整形数字。
    Varint的最小单位是byte,即8位,每byte第一位(msb)是标志位用于标记是否还有后续byte。

    ===1===
    0000 0001
    ===300===
    1010 1100  0000 0010
    

    上面300的例子首先读入第一个字节发现第一位为1,表示还有后续byte,然后读取后一个byte,第一位为0就判断已经读完,然后组装数值将其余位数取出0101100 0000010,然后反转并拼接成为000 0010-010 1100,这样就组成了300。

    其他类型

    负数,sint与int

    在protobuf的定义中sint和int似乎看上去是重复的,但其实这两种类型的底层编码式不同的。这里以-3为例:
    -3使用int编码会变成FD FF FF FF FF FF FF FF FF 01,首先这也是varint编码去掉每个byte的首位标志位然后反转顺序就成了FF FF FF FF FF FF FF FD是-3的补码。
    而使用sint编码会变成05,貌似和-3没有关系,其实它是-3经过一个zigzag转换而得来的。

    Signed OriginalEncoded As
    00
    -11
    12
    -23
    21474836474294967294
    -21474836484294967295
    这样转换可以大大减少负数的表示长度,所以建议在经常出现负数的地方使用sint而不是int可以缩短编码的大小。 ###非varient数值 对于double/fixed64,float/fixed32会分别使用固定的64位或32位进行表示。 ###不定长数据类型 对于string,byte等类型,就使用这种类型,首先使用一个varint表示长度,之后是数据的内容,列入字符串aaa就是03 61 61 61 其中03表示长度为3,61是a的utf8编码。值得注意的是,嵌套的message类型、repeat字段也都是使用这种形式进行编码到对象中的。

    message编码

    有了上面这些在准备,我们可以进入真正的消息的编码了。protobuf中每个字段都是根据定义的tag来进行定位的,在序列化的数据中,每个字段首先是一个Varint用于标记tag,其中最后三位使用来标志该字段的数据类型。

    TypeMeaningUsed For
    0Varintint32, int64, uint32, uint64, sint32, sint64, bool, enum
    164-bitfixed64, sfixed64, double
    2Length-delimitedstring, bytes, embedded messages, packed repeated fields
    3Start groupgroups (deprecated)
    4End groupgroups (deprecated)
    532-bitfixed32, sfixed32, float

    前面的位数用于标志tag,例如0000 1000,去掉第一个标志位后三个类型位,就表示tag为1的字段。
    对于repeat类型由于历史原因,proto2中默认是将数组元素并排排列在内的例如[1,2,3]会保存成[08 01 08 02 08 03]。后来对repeat类型进行了改进引入packed在定义的后面加上packed:

    repeated int32 int = 1 [packed=true];
    

    这样序列化的数据就成了0A 03 01 02 03,其中0A表示使用不定长编码,之后03表示长度,接下来是数据,就这个例子就能节约1byte。packed只适用于varint或固定长度数值表示的字段,对于string或者嵌套类型不适用,在proto3中支持的类型默认会使用packed。

    实例

    syntax = "proto2";
    message Person {
    	required string name=1;
    	required int32 age=2;
    	repeated Address add=3;	
    }
    message Address{
    	required string add=1;
    }
    ---实例---
    name: "MyName"
    age: 18
    add {
      add: "MyAdd1"
    }
    add {
      add: "MyAdd2"
    }
    ---Hex---
    0A 06 4D 79 4E 61 6D 65 10 12 1A 08 0A 06 4D 79 41 64 64 31 1A 08 0A 06 4D 79 41 64 64 32
    ---解释---
    0A 						//变长类型tag为1的字符串
    06						//name字段6 byte长度
    4D 79 4E 61 6D 65		//MyName
    10						//varint编码tag为2
    12						//18
    1A						//变长类型tag为3
    08						//Adress 8 byte长度
    0A						//变长类型tag为1
    06						//add字段6 byte长度
    4D 79 41 64 64 31		//MyAdd1
    1A						//变长类型tag为3
    08						//Adress 8 byte长度
    0A						//变长类型tag为1
    06						//add字段6 byte长度
    4D 79 41 64 64 32		//MyAdd2
    
  • 相关阅读:
    ZOJ 1002 Fire Net
    Uva 12889 One-Two-Three
    URAL 1881 Long problem statement
    URAL 1880 Psych Up's Eigenvalues
    URAL 1877 Bicycle Codes
    URAL 1876 Centipede's Morning
    URAL 1873. GOV Chronicles
    Uva 839 Not so Mobile
    Uva 679 Dropping Balls
    An ac a day,keep wa away
  • 原文地址:https://www.cnblogs.com/resentment/p/6617787.html
Copyright © 2011-2022 走看看