• protobuf编码


     

     proto2

    Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。

    字段规则

    • required: 字段必须存在
    • optional: 字段没有或有一个
    • repeated: 字段重复,0个或多个

    proto 数据类型

    .proto Type
    Notes
    C++ Type
    Java Type
    Python Type[2]
    Go Type
    double 固定8字节长度 double double float *float64
    float 固定4字节长度 float float float *float32
    int32 可变长度编码。对负数编码低效,如果字段可能是负数,用sint32代替 int32 int int *int32
    int64 可变长度编码。对负数编码低效,如果字段可能是负数,用sint64代替 int64 long int/long[3] *int64
    uint32 可变长度编码,无符号整数 uint32 int[1] int/long[3] *uint32
    uint64 可变长度编码,无符号整数 uint64 long[1] int/long[3] *uint64
    sint32 可变长度编码。有符号整数。 These more efficiently encode negative numbers than regular int32s. int32 int int *int32
    sint64 可变长度编码。有符号整数。These more efficiently encode negative numbers than regular int64s. int64 long int/long[3] *int64
    fixed32 固定4字节长度,无符号整数。 More efficient than uint32 if values are often greater than 228. uint32 int[1] int/long[3] *uint32
    fixed64 固定8字节长度,无符号整数。 More efficient than uint64 if values are often greater than 256. uint64 long[1] int/long[3] *uint64
    sfixed32 固定4字节长度,有符号整数 int32 int int *int32
    sfixed64 固定8字节长度,有符号整数 int64 long int/long[3] *int64
    bool   bool boolean bool *bool
    string UTF-8 encoded or 7-bit ASCII text. string String str/unicode[4] *string
    bytes 包含任意字节序列 string ByteString str []byte

    编码规则

    1.varints

    理解简单protobuf编码,首先要知道varints。varints使用一个字节或多个字节对整数序列化方法。

    varints中的每个字节除了最后一个字节,有一个最有效位(most significant bit ,msb),这意味指示之后有其他字节。每个字节的低7位一组数的补码

    例如:

    1

    0000  0001

    300

    1010  1100  0000  0010

    只取每个字节低七位

    010  1100  000  0010

    小端序->大端序

    000  0010  010  1100 -->  0001  0010  1100  =300

    2.消息结构

    protobuf 消息是一系列key-value对,对于二进制消息,字段数字作为关键字。字段的命名和类型在解码时确定。

    在进行消息编码时,key/value被连接成字节流。在解码时,解析器可以直接跳过不识别的字段,这样就可以保证新老版本消息定义在新老程序之间的兼容性,从而有效的避免了使用older消息格式的older程序在解析newer程序发来的newer消息时,一旦遇到未知(新添加的)字段时而引发的解析和对象初始化的错误。最后,我们介绍一下字段标号和字段类型是如何进行编码的。每一个 wire-format消息的key实际上是有两个值组成:proto文件中定义的字段标号和wire type。

    Type
    Meaning
    Used For
    0 Varint int32, int64, uint32, uint64, sint32, sint64, bool, enum
    1 64-bit fixed64, sfixed64, double
    2 Length-delimited string, bytes, embedded messages, packed repeated fields
    3 Start group groups (deprecated)
    4 End group groups (deprecated)
    5 32-bit fixed32, sfixed32, float

    key = (field_number << 3) | wire_type key的最后3个bits用于存储字段的类型信息。那么在使用该编码时,Protocol Buffer所支持的字段类型将不会超过8种。

    例如:150(十进制) 在protobuf二进制文件中是 08 96 01

    08 --> 00001000  field_number=1,wire_type=0

    96 01 -> 1001 0110  0000 0001 -->  001 0110   000  0001  -->  000 0001   001  0110   --> 1001  0110 =150

    3.Signed Integers

    wire_type=0 的类型都以varint 进行编码,所以对于int32和int64,对于负数使用补码,int32 需要5个字节,int64需要10个字节,有符号整数使用ZIgZag编码

    ZigZag 将有符号整数映射到无符号整数,以此得到一个绝对值较小的数字(例如-1)j就可以获得一个较小的varint编码值。

    Signed Original
    Encoded As
    0 0
    -1 1
    1 2
    -2 3
    2147483647 4294967294
    -2147483648 4294967295

    sint32:       (<< 1) ^ (>> 31)

     sint64:       (<< 1) ^ (>> 63)

    4.Non-varint Numbers

    wire-type=1:fixed64, sfixed64, double 固定64bit

    wire-type=5:fixed32, sfixed32, float,固定32bit

    5.Strings

    wire-type=2,字符串长度使用varint编码

    例如

    message Test2 {
      optional string b = 2;
    }

    b=“testing” ,编码后结果:

    12 07 74 65 73 74 69 6e 67

    12: field number=2,wire-type=2  (2<< 3)|2=0x12

    长度为7 varint编码 0x07

    74 65 73 74 69 6e 67  UTF8 编码

    6.Embedded Messages嵌套消息

    wire-type=2
    message Test1 {
      optional int32 a = 1;
    }
    message Test3 {
      optional Test1 c = 3;
    }

    Test1's a field set to 150

    Test3 编码结果: 1a 03 08 96 01

    1a: field_number=3,wire_type=2  (3<< 3)|2=11010=0x1a

    03: 字节数

    08 96 01 : c编码结果

    7.Optional And Repeated Elements

    proto2 :消息被定义repeated (没有 [packed=true]选项),编码的消息有0或多个使用相同字段标号的key-value对,这些重复的值不必连续出现; 他们可能会与其他字段交错,但在解码时顺序保留

    optional字段,编码后的消息可能有也可能没有包含该字段号的键值对。

    proto3 使用packed encoding:

    包含零个元素的打包重复字段不会出现在编码消息中。这个字段的所有元素都打包到一个wire-type=2的key-value对中

    message Test4 {
      repeated int32 d = 4 [packed=true];
    }
    22        // key (field number 4, wire type 2)
    06        // payload size (6 bytes)
    03        // first element (varint 3)
    8E 02     // second element (varint 270)
    9E A7 05  // third element (varint 86942)

    proto2默认不设置 packed=true
    repeated编码采用空格(0x20)分隔
    结果是20 03 20 8e 02 20 9e a7  05
  • 相关阅读:
    Outdated Kotlin Runtime
    安装 intelliJ idea 。 快速学会kotlin
    配置lambda
    kotlin 安装 使用
    android stuidio 导入项目问题。
    下载 ....aar jitpack.io 打不开。
    android studio 汉化包 美化包
    安卓架构 视频
    剑指offer-把二叉树打印成多行
    剑指offer-整数中1出现的次数(从1到n整数中1出现的次数)
  • 原文地址:https://www.cnblogs.com/dj0325/p/9238025.html
Copyright © 2020-2023  润新知