protobuf 数据解析的2种方法

方法1:

message person
{
required int32 age = 1;
required int32 userid = 2;
optional string name = 3;
}

message test
{
required int32 time = 1;
required int32 userid = 2;
required float price = 3;
optional string desc = 4;
}

  1 #include <string>
  2 #include <iostream>
  3 #include <assert.h>
  4 #include <stdint.h>
  5 
  6 #include "person.pb.h"
  7 #include "test.pb.h"
  8 
  9 using namespace std;
 10 
 11 class ProtoMsgHandle
 12 {
 13 public:
 14     /*  注册消息处理函数 */
 15     void    initHandles()
 16     {
 17         registerHandle(&ProtoMsgHandle::handleProtoPerson);
 18         registerHandle(&ProtoMsgHandle::handleProtoTest);
 19     }
 20 
 21     /*  处理网络消息
 22      *  data 为一个完整的数据包
 23      */
 24     void    handle(const char* data)
 25     {
 26         bool ret = false;
 27 
 28         const char * current=data;
 29 
 30         //在网络上传输的一个数据包总长度
 31         int packetLength=0;
 32 
 33         //从第一个位置上获取到数据包总长度
 34         memcpy(&packetLength, data, sizeof(int32_t));
 35 
 36         //指针后移
 37         current+=sizeof(int32_t);
 38 
 39         //Message名字的长度
 40         int protoNameLength=0;
 41 
 42         //从第二个位置上获取Message的名字的长度
 43         memcpy(&protoNameLength, current, sizeof(int32_t));
 44 
 45         //指针后移
 46         current+=sizeof(int32_t);
 47 
 48         //从第三个位置上获取Message的名字
 49         string name(current,protoNameLength);
 50 
 51         //指针后移
 52         current+=protoNameLength;
 53 
 54         //取得Message的字节数
 55         int messageSize=packetLength-(sizeof(int32_t)+sizeof(int32_t)+protoNameLength);
 56 
 57         do{
 58 
 59             msg_handle callback = m_callbacks[name];
 60 
 61             assert(callback != NULL);
 62 
 63             if(callback == NULL)
 64             {
 65                 std::cout<<"proto "<<name<<" had not register handler"<<std::endl;
 66                 break;
 67             }
 68             const ::google::protobuf::Descriptor* descriptor = m_descriptors[name];
 69             assert(descriptor != NULL);
 70             if(descriptor == NULL)
 71             {
 72                 std::cout<<"proto "<<name<<" had no descriptor"<<std::endl;
 73                 break;
 74             }
 75             const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
 76             assert(prototype != NULL);
 77             if(prototype == NULL)
 78             {
 79                 std::cout<<"proto "<<name<<" had no prototype"<<std::endl;
 80                 break;
 81             }
 82             google::protobuf::Message* msg = prototype->New();
 83             ret = msg->ParseFromArray(current,messageSize);
 84             if(ret)
 85             {
 86                 (this->*callback)(msg);
 87             }
 88             else
 89             {
 90                 std::cout<<"proto "<<name<<" parse fail"<<std::endl;
 91             }
 92 
 93         }while(0);
 94     }
 95 private:
 96     void handleProtoTest(test* test)
 97     {
 98         cout <<"test->price()="<< test->price() << endl;
 99         cout << "test->userid()="<<test->userid() << endl;
100         cout << "test->time()="<<test->time() << endl;
101     }
102     void handleProtoPerson(person* person)
103     {
104         cout << "person->age()="<<person->age() << endl;
105         cout << "person->userid()="<<person->userid() << endl;
106         cout << "person->name()="<<person->name() << endl;
107     }
108 
109 private:
110 
111     typedef void (ProtoMsgHandle::*msg_handle)(::google::protobuf::Message*);
112 
113     map<string, msg_handle>                                 m_callbacks;
114 
115     map<string, const ::google::protobuf::Descriptor*>      m_descriptors;
116 
117     template<typename MSGTYPE> void registerHandle(void (ProtoMsgHandle::*callback)(MSGTYPE*))
118     {
119         const ::google::protobuf::Descriptor*des =MSGTYPE::descriptor();
120         assert(des != NULL);
121         if(des != NULL)
122         {
123             m_callbacks[des->full_name()] = (msg_handle)callback;
124             m_descriptors[des->full_name()] = des;
125         }
126     }
127 
128 
129 };
130 
131 class ProtoMessageSender
132 {
133 public:
134     /*  发送proto msg到指定缓冲区
135      *  int32_t   packetLength 数据包总长度
136      *  int32_t   messageNameLength 消息名长度
137      *  char[]    messageName 消息名
138      *  char[]    Message 消息
139      *  char*     buffer 缓冲区
140      *  int       maxLength 消息的最大长度
141      */
142     template<typename MSGTYPE> static int sendMessageToBuffer(MSGTYPE& msg, char* buffer, int maxLength){
143 
144         char * current=buffer;
145 
146         //Message的字节数
147         int messageSize=msg.ByteSize();
148 
149         //Message的名字
150         string messageName=MSGTYPE::descriptor()->full_name();
151 
152         //Message名字的长度
153         size_t messageNameLength=messageName.size();
154 
155         //消息组成 messageSize+messageNameLength+messageName+Message
156         size_t packetLength=sizeof(int32_t)+sizeof(int32_t)+messageNameLength+messageSize;
157 
158         if (packetLength>maxLength) {
159             return -1;
160         }
161 
162         //将数据包总长度放在第一个位置
163         memcpy(current, &packetLength, sizeof(int32_t));
164 
165         //指针后移
166         current+=sizeof(int32_t);
167 
168         //将Message名称长度放在第二个位置
169         memcpy(current, &messageNameLength, sizeof(int32_t));
170 
171         //指针后移
172         current+=sizeof(int32_t);
173 
174         //将协议名称放在第三个位置上
175         strcpy(current,messageName.c_str());
176 
177         //指针后移
178         current+=messageNameLength;
179 
180         //将Message放在第四个位置上
181         msg.SerializeToArray(current,messageSize);
182 
183         return (int)packetLength;
184 
185     }
186 };
187 
188 int main()
189 {
190 
191     ProtoMsgHandle msghandle;
192     msghandle.initHandles();
193 
194     test t;
195     t.set_price(100.0);
196     t.set_userid(110);
197     t.set_time(123);
198 
199     person person;
200     person.set_age(18);
201     person.set_userid(200508);
202     person.set_name("irons");
203 
204     char tmp[10*1024];
205     ProtoMessageSender::sendMessageToBuffer(t, tmp, sizeof(tmp));
206     msghandle.handle(tmp);
207 
208     ProtoMessageSender::sendMessageToBuffer(person, tmp, sizeof(tmp));
209     msghandle.handle(tmp);
210 
211     cin.get();
212     return 0;
213 }

方法2:

http://my.oschina.net/cxh3905/blog/159122

比较:

方法1把每种消息注册到链表中,当有消息来时,迭代处理,每个消息对应一个回调函数。

方法2只有1种消息,里面有个成员msg type,根据这个type做相应的处理。

前者更直观,结构清晰,每个消息占用空间合理,但效率地下。

后者效率更高,但所有数据混杂在一起,代码阅读性差。

原文地址:https://www.cnblogs.com/wjx0912/p/5601073.html