读完https://developers.google.com/protocol-buffers/docs/proto,有以下心得:
1 default value。bool的默认值是false,数值的默认值是0,enum的默认值是其第一个元素,string的默认值是空字符串。
2 tag id. id 1-15占用1个字节,16到2047占用两个字节。所以1-15要留个频繁使用的字段,不要刚开始定义字段的是时候都分配出去。
tag值最小是1, 最大是(2^29 - 1)即536,870,911,但是要避开19000到19999,这是protobuf内置的类型要用到的tag id。
3 enum可以有alias。enum的值不能为负数。
enum EnumAllowingAlias {
option allow_alias = true;
UNKNOWN = 0;
STARTED = 1;
RUNNING = 1;
}
enum EnumNotAllowingAlias {
UNKNOWN = 0;
STARTED = 1;
// RUNNING = 1; // Uncommenting this line will cause a compile error inside Google and a warning message outside.
}
4 当协议更新的时候,如果某个字段过时了,就可以更改field的name,如"OBSOLETE_xxx",以告诉使用者不要在使用这个field。
也可以更改field type,前提是tag id不变,这些类型就是兼容的(之所以能兼容,按照我的理解,一个field就是一个kay-value对,tag id为key,value即为值,而type只是在序列化和反序列化的时候起到解释值的作用,并无其他作用;key = (tag << 3) | wire_type,即类型占用最多3个字节,所以有上面的tag范围是2^29 - 1)。如下几个类型是兼容的:
A int32 uint32 int64 uint64 bool
B sint32 siint64
C string bytes (字符类型是UTF8)
D fixed32 sfixed32 fixed64 sfixed64
E optional repeated
F default([default = value])value也可以被修改
5 protoc --proto-path= --cpp_out= --java_out= file.proto
--proto-path可以被-I代替。
6 protobuf对repeated压缩不够好,所以尽量在后面加上[packed = true]。
7 序列化的时候不能把多个message序列化后的内容放在一起发出去,尽量以len1 + msg1 + len2 + msg2这种形式发送。