文章目錄

protocol buffer虽然很好用,但是每次修改proto文件之后就需要重新编译生成消息代码,然后再相应的修改应用程序,用久了就有了繁琐的感觉,还好protocol buffer也提供了动态解析的功能,虽然效率低了点,但也是可以接受的(用protocol buffer3.0测试大概慢了5倍左右)。

proto文件如下,my.proto

1
2
3
4
5
6
syntax = "proto3";  
message mymsg
{
uint32 len = 1;
uint32 typ = 2;
}

动态编码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>  
#include <string>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/dynamic_message.h>
#include <google/protobuf/compiler/importer.h>

using namespace std;
using namespace google::protobuf;
using namespace google::protobuf::compiler;

int main()
{

DiskSourceTree sourceTree;
sourceTree.MapPath("", "./");
Importer importer(&sourceTree, NULL);
importer.Import("my.proto");
const Descriptor *descriptor = importer.pool()->FindMessageTypeByName("mymsg");
cout << descriptor->DebugString();
DynamicMessageFactory factory;
const Message *message = factory.GetPrototype(descriptor);
const FieldDescriptor *field = NULL;
field = descriptor->FindFieldByName("len");
const FieldDescriptor *field1 = NULL;
field1 = descriptor->FindFieldByName("typ");
Message *msg = message->New();
const Reflection *reflection = msg->GetReflection();
reflection->SetUInt32(msg, field, 1);
reflection->SetUInt32(msg, field1, 2);
std::string sout;
msg.SerializeToString(&sout);
delete msg;

return 0;
}

动态解析

1
2
3
4
5
6
7
8
9
Message *msg = message->New();  
msg->ParseFromString(sout);
const Reflection *reflection = msg->GetReflection();
const FieldDescriptor *field = NULL;
field = descriptor->FindFieldByName("len");
reflection->GetUInt32(*msg, field);
field = descriptor->FindFieldByName("typ");
reflection->GetUInt32(*msg, field);
delete msg;

其中message的获取方式和上面编码的代码一样。

动态生成消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
FileDescriptorProto file_proto;  
file_proto.set_name("my.proto");
file_proto.set_syntax("proto3");

DescriptorProto *message_proto = file_proto.add_message_type();
message_proto->set_name("mymsg");

FieldDescriptorProto *field_proto = NULL;

field_proto = message_proto->add_field();
field_proto->set_name("len");
field_proto->set_type(FieldDescriptorProto::TYPE_UINT32);
field_proto->set_number(1);
field_proto->set_label(FieldDescriptorProto::LABEL_OPTIONAL);

field_proto = message_proto->add_field();
field_proto->set_name("typ");
field_proto->set_type(FieldDescriptorProto::TYPE_UINT32);
field_proto->set_number(2);

DescriptorPool pool;
const FileDescriptor *file_descriptor = pool.BuildFile(file_proto);
cout << file_descriptor->DebugString();

上面代码所生成的结构和最开始的my.proto文件是一样的。

通过这三种方式就可以动态生成动态解析所有的内容了。

本文参考内容http://www.searchtb.com/2012/09/protocol-buffers.html

文章目錄