工作中用到了protobuf,然后之前在面试的时候面试官就问了一个问题,如果将int32类型的字段的值设置为0,那还会将该值进行序列化吗?当时是懵了的,因为自己还没有研究这部分。当时给的结果是不会,猜测protobuf中int32的默认值是0,既然默认值是0的,那应该就不会进行序列化了。
那次面试之后就觉得自己应该了解一下这部分了,结果这两天了解完之后,发现自己猜错了。好记性不如烂笔头,也顺便记录下这两天了解到的吧。如果觉得写得有点乱了,请原谅。这里使用的是protobuf版本是2.6.1。
1. protobuf简单介绍
即Protocol Buffer,是一个灵活的、高效的、自动化的用于对结构化数据进行序列化的协议,与XML相比,Protocol buffers序列化后的码流更小、速度更快、操作更简单,还是支持向前兼容和向后兼容的。
protobuf中使用了反射机制,可以根据字段的名字直接得到字段的值,更深入的我还没有了解,所以需要大家去百度下了。后面了解完的话,我会再写篇博客介绍的。
一个简单的proto文件内容如下:
message PbInfo
{
optional uint64 uid = 1;
optional uint32 time = 2;
optional uint32 type = 3;
required string account = 5;
repeated string key = 7;
}
可以看到每个字段都是由字段规则、字段类型、字段值、字段的编号组成,字段的规则有三种:optional fields(可选字段)、required fields(必须字段)、repeated fields(可重复字段),message内每个字段的编号都要是唯一的。
那protobuf是怎么做到向前及向后兼容的呢?靠的就是这个字段的编号,在反序列化的时候,protobuf会从输入流中读取出字段编号,然后再设置message中对应的值。如果读出来的字段编号是message中没有的,就直接忽略,如果message中有字段编号是输入流中没有的,则该字段不会被设置。所以即使通信的两端存在一方比另一方多出编号,也不会影响反序列化。但是如果两端同一编号的字段规则或者字段类型不一样,那就肯定会影响反序列化了。所以一般调整proto文件的时候,尽量选择加字段或者删字段,而不是修改字段编号或者字段类型。
2. protobuf怎么知道哪些字段需要序列化
下面的代码,是上面的文件编译生成c文件的一部分。
inline bool PbInfo::has_uid() const {
return (_has_bits_[0] & 0x00000001u) != 0;
}
inline void PbInfo::set_has_uid() {
_has_bits_[0] |= 0x00000001u;
}
inline void PbInfo::clear_has_uid() {
_h