protobuf 未知字段的获取
未知字段就是服务器可能新增了一个字段,但是客服端的proto文件中并没有添加,那么服务器发来的序列化数据,在客服端进行反序列化之后,这个新增的字段在proto3.5之前是会被之久抛弃的,但是在proto3.5之后会被保存哎未知字段中。那么这里的未知字段就可以理解为解析结构良好的 protocol buffer 已序列化数据中的未识别字段的表示方式。例如,当旧程序解析带有新字段的数据时,这些新字段就会成为旧程序的未知字段。
那么未知字段要从哪里获取呢?
先了解一下protobuf的相关类的关系图
MessageLite类主要提供了序列化和反序列化的方法。
Message类主要提供了GetDescriptor/GetReflection,可以获取该类型对应的Descriptor对象指针 和 Reflection 对象指针。
Desriptor类主要提供了对Message类型定义的描述,包括Message的名字、所有字段的描述、原始的proto⽂件内容等。
Reflection类主要提供了动态读写消息字段的接口。并且还包含了对未知字段的读写方法。
UnknownFieldSet类就包含了分析消息时遇到但未由其类型定义的所有字段。通过Refiection中的GetUnknownFields方法就可以返回这样一个对象,参数为消息对象。
UnknownField类中就包含了未知消息的具体内容。并且这个类中存在Type枚举类型,其中就包含了很多的未知字段的可能类型,我们选哟根据类型调用不同的方法来拿到未知字段的内容。
有了上述的理解之后就可以尝试拿一下未知字段的内容了,假设我们现在有一个PeopleInfo消息在contacts命名空间中,现在有一个消息实例peo,那么可以通过下述代码来拿到未知消息字段的变好以及内容。
// 获取到Reflection类对象const google::protobuf::Reflection* refiection = contacts::PeopleInfo::GetReflection();// 通过Reflection对象获取到未知字段的setconst google::protobuf::UnknownFieldSet& unknowSet = refiection->GetUnknownFields(peo); // 这里的消息可以替换成具体的消息,要和上面的PeopleInfo匹配for(int i = 0; i < unknowSet.field_count(); ++i){// 获取到set中的所有未知对象google::protobuf::UnknownField field = unknowSet.field(i);cout << "未知字段" << i + 1 << "字段编号为 :" << field.number() << " 值 :";// 根据类型进行打印switch (field.type()){case google::protobuf::UnknownField::Type::TYPE_VARINT:cout << field.varint() << endl;break;case google::protobuf::UnknownField::Type::TYPE_FIXED32:cout << field.fixed32() << endl;break;case google::protobuf::UnknownField::Type::TYPE_FIXED64:cout << field.fixed64() << endl;break;case google::protobuf::UnknownField::Type::TYPE_LENGTH_DELIMITED:cout << field.length_delimited() << endl;break;case google::protobuf::UnknownField::Type::TYPE_GROUP:const google::protobuf::UnknownFieldSet& set = field.group();// 这里会获得一个UnknownFieldSet 通过类似的方法进行打印break;default:break;}}