开发者文档笔记
- protobuf向后兼容,增加新字段不影响旧的代码的解析过程,旧代码会忽略它
- 每个字段后面的数字(tag)用来在序列化后的二进制中标识这个字段。在1-15的tag占用1个字节(wiretype占3位,最高有效位被占用),所以常用字段要设置较小的tag
- 谨慎使用required,使用requied但是没有传值的话,可能message会被拒绝或扔掉,所以应该在应用层代码中自己校验完整性而不是使用required。
- Reserved field:当删除.proto文件中的某字段时,这个字段的tag number 又能被继续使用,但是当其他用户引入了旧版本的.proto文件,就可能引起tag number冲突,所以推荐在删除某字段时,把该field的tag number和name都设置为reserved field,这样别人想再次使用时,编译器会报错。
- Protocol buffer编译器会根据.proto文件生成get or set field value的函数,从一个输入流中parse 得到message 或把message序列化到输出流的函数。
- 更新一个消息类型的准则.
- 不要改变已经存在的域的tag
- 任何添加的新字段应该是optional或者repeated类型.
- Non-Required字段可以被去掉,只要tag number不要被reuse
- int32, uint32, int64, uint64, and bool are all compatible
- sint32 and sint64 are compatible
- Embedded Message和bytes可以转换
- import definitions
当需要其它proto文件中的定义时,默认情况下import该文件,但不支持递归import。当把一个proto文件移到另一个位置时,不需要修改每一处对该proto文件的import,只需要在旧proto里用import public 指向新的位置,这样对旧proto的import就能依赖到新的proto。import文件的搜索路径由–proto_path标志指定
信息编码格式
基于128位varints编码
- Varints是一种用一个或更多字节序列化整数的方式
- Varints中的每个字节的最高有效位用来代表是否这个整数还有后续的字节,所以除了最后一个字节外,所有的字节的最高有效位都被设置。
- 从一个varints编码得到原始整数的方法:
比如300的编码为1010 1100 0000 0010
两个字节分别为 10101100 00000010
都去掉最高有效位 0101100 0000010
因为varints是把最低有效的字节组(去掉最高有效位后的7个字节为一个字节组,用来表示整数的值)排在前面,所以这里需要翻转一下,变为:
00000100101100, 即300.
消息结构
- 消息编码的时候,字段的field number(在.proto文件定义)和wire type(提供接下来的值所占长度的信息,比如wire type为0,代表这个值是int32类型,占4个字节,具体wire type的种类见https://developers.google.com/protocol-buffers/docs/encoding#structure)作为key,字段的值作为value,key+value一起存在编码后的数据中。Key是一个varints,按(filednumber<<3|wire type)的方式存储,也就是说,key的最低三位就是wire type。
- 有符号整数:当值为负数时,有符号整数(sint32,sin64)和int32,int64不同,当使用int32和int64时,编码后的varints为10字节长,它被对待成一个很大的无符号整数。当使用sint32和sint64时,结果varints使用zigzag编码,这更有效率。
- zigzag编码把有符号整数映射为无符号整数,使得有较小绝对值的数有较短的varints编码。
zigzag编码,每个n被映射为(n<<1)^(n>>31),这里是算术右移(右移时填充符号位),所以对负数而言,(n>>31)时全1,对正数而言时全0. - 非varint数字类型:double和fixed64为64位,float和fixed32为32位
- String类型:value为字符串的长度后面跟着实际的字符串数据
嵌套消息:被当作和string一样来看待,tag+wire type 后面跟这个嵌套消息的字节数,然后跟嵌套消息的编码 - [packed = true]选项:使repeated字段更有效的编码.
编译器生成c++代码
- 使用‘—cpp_out=dir’参数调编译器,编译器会在dir生成c++代码。
- 编译器会把.proto替换成.pb.h和.pb.cÿ