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解析 ...
随机推荐
- remount failed: Operation not permitted ,怎么办呢?
remount failed: Operation not permitted ,怎么办呢? 1. 确定是否正确连接手机了$ adb devices 2. 进入shell$ adb shell 3. ...
- 谷歌 火狐 CSS兼容
@media screen and (-webkit-min-device-pixel-ratio:0){}谷歌@-moz-document url-prefix(){}火狐
- python核心编程第六章练习6-12
6-12.字符串.(a)创建一个名字为findchr()的函数,函数声明如下.def findchr(string, char)findchr()要在字符串string中查找字符char,找到就返回该 ...
- linux笔记:shell基础-bash变量
shell变量设置规则: 变量的分类: 环境变量的设置: 系统常见环境变量: 位置参数变量(用来接收脚本的参数): 预定义变量: 接收键盘输入(将键盘输入的值赋值给变量名): 用declare声明变量 ...
- jquery获取(设置)节点的属性与属性值
1. attr(属性名) //获取属性的值(取得第一个匹配元素的属性值.通过这个方法可以方便地从第一个匹配元素中获取一个属性的值.如果元素没有相应属性,则返回 undefined ) 2 ...
- Asp.net图片文件上传
对课本上的代码进行了一点的优化 1.获取文件的名称和文件的后缀名 引用了System.IO, 用Path.GetFileNamehe()取得文件名和Path.GetExtension获取文件的后缀 2 ...
- ITPUB网站的知识索引汇总
1. ITPUB知识索引树 http://www.itpub.net/tree/ http://www.itpub.net/pubtree/index.htm 2. ITPUB知识索引贴——全文索引 ...
- 三星在GPL下发布其exFAT文件系统实现源码
exFAT文件系统是微软的一个产品,设计让外置储存设备和PC之间实现无缝的TB级数据转移和数据交换,它只支持Windows和OS X,不支持Linux.作为一个含有大量专利的私有产品,没有人会预计它会 ...
- F2工作流引擎模型
工作流引擎(Workflow Engine ) [编辑] 工作流引擎概述 工作流引擎是指workflow(工作流)作为应用系统的一部分,并为之提供对各应用系统有决定作用的根据角色.分工和条件的不同决定 ...
- C#微信开发-微信JS-SDK(1)之通过config接口注入权限验证配置
官方文档是微信JS-SDK的使用步骤http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html#JSSDK.E4.BD.B ...