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;
}
#include <string>
#include <iostream>
#include <assert.h>
#include <stdint.h> #include "person.pb.h"
#include "test.pb.h" using namespace std; class ProtoMsgHandle
{
public:
/* 注册消息处理函数 */
void initHandles()
{
registerHandle(&ProtoMsgHandle::handleProtoPerson);
registerHandle(&ProtoMsgHandle::handleProtoTest);
} /* 处理网络消息
* data 为一个完整的数据包
*/
void handle(const char* data)
{
bool ret = false; const char * current=data; //在网络上传输的一个数据包总长度
int packetLength=; //从第一个位置上获取到数据包总长度
memcpy(&packetLength, data, sizeof(int32_t)); //指针后移
current+=sizeof(int32_t); //Message名字的长度
int protoNameLength=; //从第二个位置上获取Message的名字的长度
memcpy(&protoNameLength, current, sizeof(int32_t)); //指针后移
current+=sizeof(int32_t); //从第三个位置上获取Message的名字
string name(current,protoNameLength); //指针后移
current+=protoNameLength; //取得Message的字节数
int messageSize=packetLength-(sizeof(int32_t)+sizeof(int32_t)+protoNameLength); do{ msg_handle callback = m_callbacks[name]; assert(callback != NULL); if(callback == NULL)
{
std::cout<<"proto "<<name<<" had not register handler"<<std::endl;
break;
}
const ::google::protobuf::Descriptor* descriptor = m_descriptors[name];
assert(descriptor != NULL);
if(descriptor == NULL)
{
std::cout<<"proto "<<name<<" had no descriptor"<<std::endl;
break;
}
const google::protobuf::Message* prototype = google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
assert(prototype != NULL);
if(prototype == NULL)
{
std::cout<<"proto "<<name<<" had no prototype"<<std::endl;
break;
}
google::protobuf::Message* msg = prototype->New();
ret = msg->ParseFromArray(current,messageSize);
if(ret)
{
(this->*callback)(msg);
}
else
{
std::cout<<"proto "<<name<<" parse fail"<<std::endl;
} }while();
}
private:
void handleProtoTest(test* test)
{
cout <<"test->price()="<< test->price() << endl;
cout << "test->userid()="<<test->userid() << endl;
cout << "test->time()="<<test->time() << endl;
}
void handleProtoPerson(person* person)
{
cout << "person->age()="<<person->age() << endl;
cout << "person->userid()="<<person->userid() << endl;
cout << "person->name()="<<person->name() << endl;
} private: typedef void (ProtoMsgHandle::*msg_handle)(::google::protobuf::Message*); map<string, msg_handle> m_callbacks; map<string, const ::google::protobuf::Descriptor*> m_descriptors; template<typename MSGTYPE> void registerHandle(void (ProtoMsgHandle::*callback)(MSGTYPE*))
{
const ::google::protobuf::Descriptor*des =MSGTYPE::descriptor();
assert(des != NULL);
if(des != NULL)
{
m_callbacks[des->full_name()] = (msg_handle)callback;
m_descriptors[des->full_name()] = des;
}
} }; class ProtoMessageSender
{
public:
/* 发送proto msg到指定缓冲区
* int32_t packetLength 数据包总长度
* int32_t messageNameLength 消息名长度
* char[] messageName 消息名
* char[] Message 消息
* char* buffer 缓冲区
* int maxLength 消息的最大长度
*/
template<typename MSGTYPE> static int sendMessageToBuffer(MSGTYPE& msg, char* buffer, int maxLength){ char * current=buffer; //Message的字节数
int messageSize=msg.ByteSize(); //Message的名字
string messageName=MSGTYPE::descriptor()->full_name(); //Message名字的长度
size_t messageNameLength=messageName.size(); //消息组成 messageSize+messageNameLength+messageName+Message
size_t packetLength=sizeof(int32_t)+sizeof(int32_t)+messageNameLength+messageSize; if (packetLength>maxLength) {
return -;
} //将数据包总长度放在第一个位置
memcpy(current, &packetLength, sizeof(int32_t)); //指针后移
current+=sizeof(int32_t); //将Message名称长度放在第二个位置
memcpy(current, &messageNameLength, sizeof(int32_t)); //指针后移
current+=sizeof(int32_t); //将协议名称放在第三个位置上
strcpy(current,messageName.c_str()); //指针后移
current+=messageNameLength; //将Message放在第四个位置上
msg.SerializeToArray(current,messageSize); return (int)packetLength; }
}; int main()
{ ProtoMsgHandle msghandle;
msghandle.initHandles(); test t;
t.set_price(100.0);
t.set_userid();
t.set_time(); person person;
person.set_age();
person.set_userid();
person.set_name("irons"); char tmp[*];
ProtoMessageSender::sendMessageToBuffer(t, tmp, sizeof(tmp));
msghandle.handle(tmp); ProtoMessageSender::sendMessageToBuffer(person, tmp, sizeof(tmp));
msghandle.handle(tmp); cin.get();
return ;
}
方法2:
http://my.oschina.net/cxh3905/blog/159122
比较:
方法1把每种消息注册到链表中,当有消息来时,迭代处理,每个消息对应一个回调函数。
方法2只有1种消息,里面有个成员msg type,根据这个type做相应的处理。
前者更直观,结构清晰,每个消息占用空间合理,但效率地下。
后者效率更高,但所有数据混杂在一起,代码阅读性差。
protobuf 数据解析的2种方法的更多相关文章
- IOS - JSON数据解析 小3种方法
[manager GET:serverURL parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject ...
- Android数据存储的五种方法汇总
本文介绍Android中的5种数据存储方式. 数据存储在开发中是使用最频繁的,在这里主要介绍Android平台中实现数据存储的5种方式,分别是: 1 使用SharedPreferences存储数据 2 ...
- python实现XML解析的三种方法
python实现XML解析的三种方法 三种方法:一是xml.dom.*模块,它是W3C DOM API的实现,若需要处理DOM API则该模块很适合:二是xml.sax.*模块,它是SAX API的实 ...
- Android之数据存储的五种方法
1.Android数据存储的五种方法 (1)SharedPreferences数据存储 详情介绍:http://www.cnblogs.com/zhangmiao14/p/6201900.html 优 ...
- 解析Xml四种方法
关键字:Java解析xml.解析xml四种方法.DOM.SAX.JDOM.DOM4j.XPath [引言] 目前在Java中用于解析XML的技术很多,主流的有DOM.SAX.JDOM.DOM4j,下文 ...
- IOS开发中数据持久化的几种方法--NSUserDefaults
IOS开发中数据持久化的几种方法--NSUserDefaults IOS 开发中,经常会遇到需要把一些数据保存在本地的情况,那么这个时候我们有以下几种可以选择的方案: 一.使用NSUserDefaul ...
- oracle rename数据文件的两种方法
oracle rename数据文件的两种方法 2012-12-11 20:44 10925人阅读 评论(0) 收藏 举报 分类: oracle(98) 版权声明:本文为博主原创文章,未经博主允许不 ...
- 三、用Delphi10.3 创建一条JSON数据的第三种方法,非常简洁的写法
一.用Delphi10.3构造一个JSON数据的第三种方法,并格式化输出,代码如下: uses // System.JSON, System.JSON.Types, System.JSON.Write ...
- XML解析的二种方法之dom解析
XML解析的二种方法:dom解析和sax解析 文件大小 存储位置 读取速度 dom解析 小文件 放在内存中 快 sax解析 ...
随机推荐
- MySQL数据库优化的八种方式(经典必看)
引言: 关于数据库优化,网上有不少资料和方法,但是不少质量参差不齐,有些总结的不够到位,内容冗杂 偶尔发现了这篇文章,总结得很经典,文章流量也很大,所以拿到自己的总结文集中,积累优质文章,提升个人 ...
- Android OkHttp完全解析 是时候来了解OkHttp了
Android OkHttp完全解析 是时候来了解OkHttp了 标签: AndroidOkHttp 2015-08-24 15:36 316254人阅读 评论(306) 收藏 举报 分类: [an ...
- 解决JSP路径问题的方法(jsp文件开头path, basePath作用)
原文:http://blog.csdn.net/mingxunzh/article/details/4627185 在JSP中的如果使用 "相对路径" 则有可能会出现问题. 因为 ...
- $inArray()总是返回-1
$inArray(val,arr)注意val类型和arr中的是否一致 如1 和"1" 就会返回-1
- openssl evp 哈希算法(md5,sha1,sha256)
1. 简述 openssl提供了丰富密码学工具,一些常用的哈希算法 比如md5,sha 可以直接用提供的md5.h ,sha.h 接口使用: 为了方便开发者使用,openssl 又提供了一个EVP, ...
- css学习笔记 1
对于一个页面,如何控制页面的结构就看如何去理解css的各个属性了,只有了解了css的各个属性后才能更有效的让css控制页面的任何一个结构. css的结构:选择符:{属性名1:属性值; 属性名2:属性值 ...
- openwrt 的依赖找不到问题
Openwrt报告库找不到Package * is missing dependencies for the following libraries: libc.so.6 或其他先检查系统里面有没有这 ...
- DES MAC PIN HEX
/* void DesEncrypt( UCHAR * auchInput,UCHAR * auchKey,UCHAR * auchOutput=NULL); Function: DesEncrypt ...
- 读<jquery 权威指南>[4]-Ajax
一.获取异步数据 jQuery可以从服务器异步获得静态数据. ①load() $.load(url,data,callback) url要加载的页面地址, data发送到服务器的数据key/value ...
- spring随手笔记2:初始化方法
1.init-method="init" public class HelloWorldServiceImpl implements HelloWorldService { pri ...