zoukankan      html  css  js  c++  java
  • 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做相应的处理。

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

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

  • 相关阅读:
    OpenWrt(LEDE)2020.4.29更新 UPnP+NAS+多拨+网盘+DNS优化+帕斯沃 无缝集成+软件包
    OpenWrt(LEDE)2020.4.12编译 UnPnP+NAS+多拨+网盘+DNS优化+帕斯沃 无缝集成
    软路由OpenWrt(LEDE)2020.4.6编译 UnPnP+NAS+多拨+网盘+DNS优化
    软路由OpenWrt(LEDE)2020.4.4编译 UnPnP+NAS+多拨+网盘+DNS优化
    【x64软路由】OpenWrt(LEDE) 20200329编译 反追踪 抗污染 加速 PSW 无缝集成 UPnP NAS
    OpenWrt R2020.3.19 反追踪 抗污染 加速 PSW 无缝集成 UnPnP NAS
    Go语言进阶学习笔记
    go语言基础学习笔记
    深入剖析PHP7内核源码(二)- PHP变量容器
    深入剖析PHP7内核源码(一)- PHP架构与生命周期
  • 原文地址:https://www.cnblogs.com/wjx0912/p/5601073.html
Copyright © 2011-2022 走看看