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解析 ...
随机推荐
- 程序设计入门——C语言 第2周编程练习 1时间换算(5分)
1 时间换算(5分) 题目内容: UTC是世界协调时,BJT是北京时间,UTC时间相当于BJT减去8.现在,你的程序要读入一个整数,表示BJT的时和分.整数的个位和十位表示分,百位和千位表示小时.如果 ...
- 高斯混合模型与EM算法
对于高斯混合模型是干什么的呢?它解决什么样的问题呢?它常用在非监督学习中,意思就是我们的训练样本集合只有数据,没有标签. 它用来解决这样的问题:我们有一堆的训练样本,这些样本可以一共分为K类,用z(i ...
- Setup Factory Error3014
在用Setup Factory打包软件的时候出现Error3014 一般都是由于软件冲突引起的 我的问题是由于杀毒软件 ,在打包的时候关闭杀毒软件 就能成功打包了.
- angular 三目运算符 需要换色或style
解决方法:直接简单粗暴写两个.有点挫,但实现需求了. <font style="color:red" ng-show="boxlist.lineTitle.leng ...
- oracle表空间不足相关问题解决办法
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- Web前端入门了解
Web就是指万维网,网站,Web开发的方向包括Web前端,Web后台. Web前端又分为 静态Web 和 动态Web, 静态Web就是用HTML实现的. 动态Web的实现方式有多种. 动态Web的实 ...
- jquery.uploadify 动态传递参数
最近 项目中使用到 uplaodify 来实现上传文件的功能.在传输动态参数的时候,遇到了问题! 使用官网提供的 settings 方法 官方例子function changeBtnText() { ...
- nodejs gulp less编辑
nodejs 下载地址:http://pan.baidu.com/s/1bnz2oPp 提取密码:0mip 1.最简单的编译less 在安装好nodejs后,cmd 进入控制台 安装 lessc : ...
- http 网络请求
/** * 用 HttpClient 的 Get 请求访问服务器 * * @param url_path * @param userN ...
- Windows 下java环境变量的配置(Windows7 ,8,8.1,10)
Windows 下java环境变量的配置 在“系统”面板的左上角选择“高级系统设置”,在弹出的系统属性中选择”高级“项,然后点击右下角的“环境变量(N)...”,就此进入JAVA环境变量的配置. 如果 ...