关于protobuff的一些理解

近期公司项目使用到了protobuff。虽然之前对protobuff就一直有耳闻,但是对传闻其高效便捷并不是很理解,直到此项目才对protobuff有了一些较为深刻的认识。

先说下protobuff的用法 以c++为示例。 关于如何下载 编译就不多说了。先生成xx.proto文件, 里面 按照格式写入你的数据结构 例如

  

message Data
 {
    required string        id          = 1;
optional int32          data1 = 2;
  repeated int32        data2   = 3;  
}

protoc.exe --cpp_out=*.proto 生成 相应的cpp 和h文件

    这里有3个字段 第一个 required  表示此字段必须赋值  如果没赋值会怎样? 其实也不会怎样生成出来的代码中 IsInitialized 会返回false。optional  表示可有可无的字段。

repeated 表示可能会重复的字段 其在代码的表现形式则是一个动态数组。关于数据类型 如下

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

 对应枚举   enum WireType {
    WIRETYPE_VARINT           = 0,
    WIRETYPE_FIXED64          = 1,
    WIRETYPE_LENGTH_DELIMITED = 2,
    WIRETYPE_START_GROUP      = 3,
    WIRETYPE_END_GROUP        = 4,
    WIRETYPE_FIXED32          = 5,
  };

当生成cpp文件时 会将你所定义的所有变量都生成在类里 如以上生成的数据 则有如下规则

Data  a; 设置某值有   a.set_id(“1”);  这里的set_id 表示对 id字段赋值  获得id则有  a.id(); 所有字段的设置和获取都雷同此方法。

那么接下来说下protobuff的打包规则,它使用的是Tag-Value模式 也就是说一个字段由2个数据表示打包出来的最后二进制数据如下 [Tag][Value][Tag][Value][Tag][Value]....... 这样做的好处是如果不用打包的数据不出现在里面即可节省了很多空间。这里要说一下protobuff使用的字段按字节来说每个字节的第1位表示后面的一个字节是否和此是关联的,也就是说如果某个字节的第一位如果是1 而后面一个字节第一位是0 那么表示这2个字节组成一个数 ,如果第二个字节的第一位也是1 而第3个字节的第1位是0 那么表示这3个字节组成一个数以此类推,所有字节的第一位都是会被protobuf使用的,除了字符串类型,字符串类型仅仅是长度+memcpy。这样做从概率学上将会在一定程度上压缩空间,因为如果是一个数值很小的数 正常的int 需要4个字节 而此时可能仅需要1个字节当然我们不能将Tag的大小忽略那么Tag最小也是1字节这样一个小数据将占用2字节就能表示。这里要注意的是一个32位 4字节的字段 protobuf是技能使用的只有28位。Tag的制作规则 ,按字节来说后面三位用来表示数据类型  也就是WireType,  前面的数字则是其字段在定义时的位置 例如 id = 1  这个1 就表示此值 。当然 这个规则也遵循7位规则,也就是一个字节的最高位会被protobuf保留使用,这样Tag能用的数值为 28 - 3=25 位 这个数字也是天文数字了。而其中当数据是重复数据 或者字符串时 会在Tag后先打包一个长度(数组长度或者字符串长度)再将数据依次打包进来。字符串比较简单memcpy到相关内存即可

数组的话则是用长度计数,某一数据是否结束用其第一位是否为0表示

这样的打包方式还有一个好处就是便于扩展 ,比如一个数据以protobuf形式存储在数据库 ,而之后功能扩展了 比如有如下格式

message Data
  {
    required string        id          = 1;
optional int32          data1 = 2;
   repeated int32        data2   = 3;  

  optional int32          data3 = 4
 }

新增了一个data3  那么程序启动时先读取此结构 按Tag - Value规则 将相关值顺利的赋值到内存中,然后data3有数据了写入数据库 则数据库记录完美更新。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值