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解析 ...
随机推荐
- laravel多国语言包
https://packagist.org/packages/caouecs/laravel-lang 例如安装中文语言包 则下载 zh-CN 拷贝文件到 resouces/lang 下 然后修改co ...
- c++ *.h和*.cpp在编译中的作用
首先,我们可以将所有东西都放在一个.cpp文件内.然后编译器就将这个.cpp编译成.obj,obj是什么东西?就是编译单元了. 一个程序,可以由一个编译单元组成,也可以有多个编译单元组成. 如果你不想 ...
- flash的动态加载技术
这里所说的动态加载技术, 主要是指代码模块(可以是swc也可以是swf)的动态加载.即主swf在运行的时候, 可以根据需要动态加载所需的代码模块. 为了讨论方便, 下面所说的代码模块都用swc表示,用 ...
- linux -- 基于mysql tomcat 部署web项目
一.导入数据库 二.配置web项目访问端口 vim /var/lib/tomcat8/conf/server.xml <Connector port=" protocol=" ...
- 运用js解决java selenium元素定位问题
一.解决定位并操作uneditable元素 尝试了通过id,xpath等等定位元素后点击都提示Element is not clickable at point 再看了下可以click的元素发现上面有 ...
- [转]深入理解Java 8 Lambda(类库篇——Streams API,Collectors和并行)
以下内容转自: 作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://zh.lucida.me/blog/java-8-lambdas-insideout-l ...
- iOS开发Swift篇—(七)函数(1)
iOS开发Swift篇—(七)函数 一.函数的定义 (1)函数的定义格式 func 函数名(形参列表) -> 返回值类型 { // 函数体... } (2)形参列表的格式 形参名1: 形参类型1 ...
- sql server 子找父和父找子
父找子 with RTD1 as( select Id,pid from Sys_XCode ), RTD2 as( select * from RTD1 where id=1 union all s ...
- ubuntu install wine
1 install sUdo add-apt-repository ppa:wine/wine-builds sudo apt-get update sudo apt-get install wine ...
- web前端基础篇⑦
1.img src/url后一般接地址信息 标题为<h1>-<h6> 字体依次变小 预文本格式<pre></pre> 2.a标签实现跳转 例:<a ...