protobuf 复杂结构体怎样传输复杂数据结构

温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
class LogonReqMessage : public ::google::protobuf::MessageLite {&public:&LogonReqMessage();&virtual ~LogonReqMessage();&// implements Message ----------------------------------------------&//下面的成员函数均实现自MessageLite中的虚函数。&//创建一个新的LogonReqMessage对象,等同于clone。&LogonReqMessage* New()&//用另外一个LogonReqMessage对象初始化当前对象,等同于赋值操作符重载(operator=)&void CopyFrom(const LogonReqMessage& from);&//清空当前对象中的所有数据,既将所有成员变量置为未初始化状态。&void Clear();&//判断当前状态是否已经初始化。&bool IsInitialized()&//在给当前对象的所有变量赋值之后,获取该对象序列化后所需要的字节数。&int ByteSize()&//获取当前对象的类型名称。&::std::string GetTypeName()&// required int64 acctID = 1;&//下面的成员函数都是因message中定义的acctID字段而生成。&//这个静态成员表示AcctID的标签值。命名规则是k + FieldName(驼峰规则) + FieldNumber。&static const int kAcctIDFieldNumber = 1;&//如果acctID字段已经被设置返回true,否则false。&inline bool has_acctid()&//执行该函数后has_acctid函数将返回false,而下面的acctid函数则返回acctID的缺省值。&inline void clear_acctid();&//返回acctid字段的当前值,如果没有设置则返回int64类型的缺省值。&inline ::google::protobuf::int64 acctid()&//为acctid字段设置新值,调用该函数后has_acctid函数将返回true。&inline void set_acctid(::google::protobuf::int64 value);&// required string passwd = 2;&//下面的成员函数都是因message中定义的passwd字段而生成。这里生成的函数和上面acctid&//生成的那组函数基本相似。因此这里只是列出差异部分。&static const int kPasswdFieldNumber = 2;&inline bool has_passwd()&inline void clear_passwd();&inline const ::std::string& passwd()&inline void set_passwd(const ::std::string& value);&//对于字符串类型字段设置const char*类型的变量值。&inline void set_passwd(const char* value);&inline void set_passwd(const char* value, size_t size);&//可以通过返回值直接给passwd对象赋值。在调用该函数之后has_passwd将返回true。&inline ::std::string* mutable_passwd();&//释放当前对象对passwd字段的所有权,同时返回passwd字段对象指针。调用此函数之后,passwd字段对象&//的所有权将移交给调用者。此后再调用has_passwd函数时将返回false。&inline ::std::string* release_passwd();&private:&... ...&};&下面是读写LogonReqMessage对象的C++测试代码和说明性注释。&复制代码 代码如下:void testSimpleMessage()&{&printf("==================This is simple message.================\n");&//序列化LogonReqMessage对象到指定的内存区域。&LogonReqMessage logonR&logonReq.set_acctid(20);&logonReq.set_passwd("Hello World");&//提前获取对象序列化所占用的空间并进行一次性分配,从而避免多次分配&//而造成的性能开销。通过该种方式,还可以将序列化后的数据进行加密。&//之后再进行持久化,或是发送到远端。&int length = logonReq.ByteSize();&char* buf = new char[length];&logonReq.SerializeToArray(buf,length);&//从内存中读取并反序列化LogonReqMessage对象,同时将结果打印出来。&LogonReqMessage logonReq2;&logonReq2.ParseFromArray(buf,length);&printf("acctID = %I64d, password = %s\n",logonReq2.acctid(),logonReq2.passwd().c_str());&delete []&}&三、嵌套message生成的C++代码&enum UserStatus {&OFFLINE = 0;&ONLINE = 1;&}&enum LoginResult {&LOGON_RESULT_SUCCESS = 0;&LOGON_RESULT_NOTEXIST = 1;&LOGON_RESULT_ERROR_PASSWD = 2;&LOGON_RESULT_ALREADY_LOGON = 3;&LOGON_RESULT_SERVER_ERROR = 4;&}&message UserInfo {&required int64 acctID = 1;&required string name = 2;&required UserStatus status = 3;&}&message LogonRespMessage {&required LoginResult logonResult = 1;&required UserInfo userInfo = 2; //这里嵌套了UserInfo消息。&}&对于上述消息生成的C++代码,UserInfo因为只是包含了原始类型字段,因此和上例中的LogonReqMessage没有太多的差别,这里也就不在重复列出了。由于LogonRespMessage消息中嵌套了UserInfo类型的字段,在这里我们将仅仅给出该消息生成的C++代码和关键性注释。&复制代码 代码如下:class LogonRespMessage : public ::google::protobuf::MessageLite {&public:&LogonRespMessage();&virtual ~LogonRespMessage();&// implements Message ----------------------------------------------&... ... //这部分函数和之前的例子一样。&// required .LoginResult logonResult = 1;&//下面的成员函数都是因message中定义的logonResult字段而生成。&//这一点和前面的例子基本相同,只是类型换做了枚举类型LoginResult。&static const int kLogonResultFieldNumber = 1;&inline bool has_logonresult()&inline void clear_logonresult();&inline LoginResult logonresult()&inline void set_logonresult(LoginResult value);&// required .UserInfo userInfo = 2;&//下面的成员函数都是因message中定义的UserInfo字段而生成。&//这里只是列出和非消息类型字段差异的部分。&static const int kUserInfoFieldNumber = 2;&inline bool has_userinfo()&inline void clear_userinfo();&inline const ::UserInfo& userinfo()&//可以看到该类并没有生成用于设置和修改userInfo字段set_userinfo函数,而是将该工作&//交给了下面的mutable_userinfo函数。因此每当调用函数之后,Protocol Buffer都会认为&//该字段的值已经被设置了,同时has_userinfo函数亦将返回true。在实际编码中,我们可以&//通过该函数返回userInfo字段的内部指针,并基于该指针完成userInfo成员变量的初始化工作。&inline ::UserInfo* mutable_userinfo();&inline ::UserInfo* release_userinfo();&private:&... ...&};&下面是读写LogonRespMessage对象的C++测试代码和说明性注释。&复制代码 代码如下:void testNestedMessage()&{&printf("==================This is nested message.================\n");&LogonRespMessage logonR&logonResp.set_logonresult(LOGON_RESULT_SUCCESS);&//如上所述,通过mutable_userinfo函数返回userInfo字段的指针,之后再初始化该对象指针。&UserInfo* userInfo = logonResp.mutable_userinfo();&userInfo-&set_acctid(200);&userInfo-&set_name("Tester");&userInfo-&set_status(OFFLINE);&int length = logonResp.ByteSize();&char* buf = new char[length];&logonResp.SerializeToArray(buf,length);&LogonRespMessage logonResp2;&logonResp2.ParseFromArray(buf,length);&printf("LogonResult = %d, UserInfo-&acctID = %I64d, UserInfo-&name = %s, UserInfo-&status = %d\n"&,logonResp2.logonresult(),logonResp2.userinfo().acctid(),logonResp2.userinfo().name().c_str(),logonResp2.userinfo().status());&delete []&}&四、repeated嵌套message生成的C++代码&message BuddyInfo {&required UserInfo userInfo = 1;&required int32 groupID = 2;&}&message RetrieveBuddiesResp {&required int32 buddiesCnt = 1;&repeated BuddyInfo buddiesInfo = 2;&}&对于上述消息生成的代码,我们将只是针对RetrieveBuddiesResp消息所对应的C++代码进行详细说明,其余部分和前面小节的例子基本相同,可直接参照。而对于RetrieveBuddiesResp类中的代码,我们也仅仅是对buddiesInfo字段生成的代码进行更为详细的解释。&复制代码 代码如下:class RetrieveBuddiesResp : public ::google::protobuf::MessageLite {&public:&RetrieveBuddiesResp();&virtual ~RetrieveBuddiesResp();&... ... //其余代码的功能性注释均可参照前面的例子。&// repeated .BuddyInfo buddiesInfo = 2;&static const int kBuddiesInfoFieldNumber = 2;&//返回数组中成员的数量。&inline int buddiesinfo_size()&//清空数组中的所有已初始化成员,调用该函数后,buddiesinfo_size函数将返回0。&inline void clear_buddiesinfo();&//返回数组中指定下标所包含元素的引用。&inline const ::BuddyInfo& buddiesinfo(int index)&//返回数组中指定下标所包含元素的指针,通过该方式可直接修改元素的值信息。&inline ::BuddyInfo* mutable_buddiesinfo(int index);&//像数组中添加一个新元素。返回值即为新增的元素,可直接对其进行初始化。&inline ::BuddyInfo* add_buddiesinfo();&//获取buddiesInfo字段所表示的容器,该函数返回的容器仅用于遍历并读取,不能直接修改。&inline const ::google::protobuf::RepeatedPtrField& ::BuddyInfo &&&buddiesinfo()&//获取buddiesInfo字段所表示的容器指针,该函数返回的容器指针可用于遍历和直接修改。&inline ::google::protobuf::RepeatedPtrField& ::BuddyInfo &*&mutable_buddiesinfo();&private:&... ...&};&下面是读写RetrieveBuddiesResp对象的C++测试代码和说明性注释。&复制代码 代码如下:void testRepeatedMessage()&{&printf("==================This is repeated message.================\n");&RetrieveBuddiesResp retrieveR&retrieveResp.set_buddiescnt(2);&BuddyInfo* buddyInfo = retrieveResp.add_buddiesinfo();&buddyInfo-&set_groupid(20);&UserInfo* userInfo = buddyInfo-&mutable_userinfo();&userInfo-&set_acctid(200);&userInfo-&set_name("user1");&userInfo-&set_status(OFFLINE);&buddyInfo = retrieveResp.add_buddiesinfo();&buddyInfo-&set_groupid(21);&userInfo = buddyInfo-&mutable_userinfo();&userInfo-&set_acctid(201);&userInfo-&set_name("user2");&userInfo-&set_status(ONLINE);&int length = retrieveResp.ByteSize();&char* buf = new char[length];&retrieveResp.SerializeToArray(buf,length);&RetrieveBuddiesResp retrieveResp2;&retrieveResp2.ParseFromArray(buf,length);&printf("BuddiesCount = %d\n",retrieveResp2.buddiescnt());&printf("Repeated Size = %d\n",retrieveResp2.buddiesinfo_size());&//这里仅提供了通过容器迭代器的方式遍历数组元素的测试代码。&//事实上,通过buddiesinfo_size和buddiesinfo函数亦可循环遍历。&RepeatedPtrField&BuddyInfo&* buddiesInfo = retrieveResp2.mutable_buddiesinfo();&RepeatedPtrField&BuddyInfo&::iterator it = buddiesInfo-&begin();&for (; it != buddiesInfo-&end(); ++it) {&printf("BuddyInfo-&groupID = %d\n", it-&groupid());&printf("UserInfo-&acctID = %I64d, UserInfo-&name = %s, UserInfo-&status = %d\n"&, it-&userinfo().acctid(), it-&userinfo().name().c_str(),it-&userinfo().status());&}&delete []&}&最后需要说明的是,Protocol Buffer仍然提供了很多其它非常有用的功能,特别是针对序列化的目的地,比如文件流和网络流等。与此同时,也提供了完整的官方文档和规范的命名规则,在很多情况下,可以直接通过函数的名字便可获悉函数所完成的工作。详细出处参考:http://www.jb51.net/article/33030.htm
阅读(6823)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'protobuf文件嵌套结构实例',
blogAbstract:'class LogonReqMessage : public ::google::protobuf::MessageLite {&public:&LogonReqMessage();&virtual ~LogonReqMessage();&// implements Message ----------------------------------------------&//下面的成员函数均实现自MessageLite中的虚函数。&//创建一个新的LogonReqMessage对象,等同于clone。&LogonReqMessage* New()&',
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:0,
publishTime:0,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}基于Protobuf的数据传输协议_论文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
基于Protobuf的数据传输协议
中国最大最早的专业内容网站|
总评分0.0|
试读已结束,如果需要继续阅读或下载,敬请购买
定制HR最喜欢的简历
你可能喜欢
您可以上传图片描述问题
联系电话:
请填写真实有效的信息,以便工作人员联系您,我们为您严格保密。65037人阅读
c/c++(24)
要通信,必须有协议,否则双方无法理解对方的码流。在protobuf中,协议是由一系列的消息组成的。因此最重要的就是定义通信时使用到的消息格式。
Protobuf消息定义
消息由至少一个字段组合而成,类似于C语言中的结构。每个字段都有一定的格式。
字段格式:限定修饰符① | 数据类型② | 字段名称③ | = | 字段编码值④ | [字段默认值⑤]
①.限定修饰符包含 required\optional\repeated
Required: 表示是一个必须字段,必须相对于发送方,在发送消息之前必须设置该字段的值,对于接收方,必须能够识别该字段的意思。发送之前没有设置required字段或者无法识别required字段都会引发编解码异常,导致消息被丢弃。
Optional:表示是一个可选字段,可选对于发送方,在发送消息时,可以有选择性的设置或者不设置该字段的值。对于接收方,如果能够识别可选字段就进行相应的处理,如果无法识别,则忽略该字段,消息中的其它字段正常处理。---因为optional字段的特性,很多接口在升级版本中都把后来添加的字段都统一的设置为optional字段,这样老的版本无需升级程序也可以正常的与新的软件进行通信,只不过新的字段无法识别而已,因为并不是每个节点都需要新的功能,因此可以做到按需升级和平滑过渡。
Repeated:表示该字段可以包含0~N个元素。其特性和optional一样,但是每一次可以包含多个值。可以看作是在传递一个数组的值。
②.数据类型
Protobuf定义了一套基本数据类型。几乎都可以映射到C++\Java等语言的基础数据类型.
protobuf 数据类型
C++语言映射
64位浮点数
32为浮点数
32位整数、
无符号32位整数
unsigned int
64为无符号整
unsigned __int64
32位整数,处理负数效率更高
64位整数 处理负数效率更高
32位无符号整数
unsigned int32
64位无符号整数
unsigned __int64
32位整数、能以更高的效率处理负数
unsigned int32
unsigned __int64
只能处理 ASCII字符
std::string
用于处理多字节的语言字符、如中文
std::string
可以包含一个用户自定义的枚举类型uint32
可以包含一个用户自定义的消息类型
object of class
N 表示打包的字节并不是固定。而是根据数据的大小或者长度。
例如int32,如果数值比较小,在0~127时,使用一个字节打包。
关于枚举的打包方式和uint32相同。
关于message,类似于C语言中的结构包含另外一个结构作为数据成员一样。
关于 fixed32 和int32的区别。fixed32的打包效率比int32的效率高,但是使用的空间一般比int32多。因此一个属于时间效率高,一个属于空间效率高。根据项目的实际情况,一般选择fixed32,如果遇到对传输数据量要求比较苛刻的环境,可以选择int32.
③.字段名称
字段名称的命名与C、C++、Java等语言的变量命名方式几乎是相同的。
protobuf建议字段的命名采用以下划线分割的驼峰式。例如 first_name 而不是firstName.
④.字段编码值
有了该值,通信双方才能互相识别对方的字段。当然相同的编码值,其限定修饰符和数据类型必须相同。
编码值的取值范围为 1~2^32()。
其中 1~15的编码时间和空间效率都是最高的,编码值越大,其编码的时间和空间效率就越低(相对于1-15),当然一般情况下相邻的2个值编码效率的是相同的,除非2个值恰好实在4字节,12字节,20字节等的临界区。比如15和16.
编码值为Google protobuf 系统内部保留值,建议不要在自己的项目中使用。
protobuf 还建议把经常要传递的值把其字段编码设置为1-15之间的值。
消息中的字段的编码值无需连续,只要是合法的,并且不能在同一个消息中有字段包含相同的编码值。
建议:项目投入运营以后涉及到版本升级时的新增消息字段全部使用optional或者repeated,尽量不实用required。如果使用了required,需要全网统一升级,如果使用optional或者repeated可以平滑升级。
⑤.默认值。当在传递数据时,对于required数据类型,如果用户没有设置值,则使用默认值传递到对端。当接受数据是,对于optional字段,如果没有接收到optional字段,则设置为默认值。
关于import
protobuf 接口文件可以像C语言的h文件一个,分离为多个,在需要的时候通过 import导入需要对文件。其行为和C语言的#include或者java的import的行为大致相同。
关于package
避免名称冲突,可以给每个文件指定一个package名称,对于java解析为java中的包。对于C++则解析为名称空间。
关于message
支持嵌套消息,消息可以包含另一个消息作为其字段。也可以在消息内定义一个新的消息。
枚举的定义和C++相同,但是有一些限制。
枚举值必须大于等于0的整数。
使用分号(;)分隔枚举变量而不是C++语言中的逗号(,)
enum VoipProtocol&
&&&&H323 = 1;
&&&&SIP&&= 2;
&&&&MGCP = 3;
&&&&H248 = 4;
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:761481次
积分:6669
积分:6669
排名:第3532名
原创:138篇
转载:172篇
评论:53条
文章:34篇
阅读:23466
(4)(4)(4)(1)(9)(4)(4)(4)(11)(10)(27)(16)(1)(5)(14)(22)(3)(1)(3)(12)(1)(1)(5)(8)(3)(2)(5)(3)(3)(2)(4)(1)(2)(5)(6)(13)(14)(4)(10)(2)(3)(16)(5)(1)(32)(3)protobuf怎样传输复杂数据结构?(c++ 与 C#) - 知乎8被浏览1327分享邀请回答02 条评论分享收藏感谢收起protobuf 复杂数据类型定义 - Pomelo Club
protobuf 复杂数据类型定义
各位好,我在处理压缩的时候有一些复杂的数据类型数组 [1,2,3,4...] 这种类型怎么定义还有一种动态的对象,key为数字,value为object或者null, 对象的大小不确定。例如: team = {1: {name:xx,age:xx}, 2:null, ...}类似的类型看文档没有对于这种数据结构的定义,不知道各位如何处理。
1:数组的话
&option&: &repeated&
2:动态对象是不支持的,要么就弄成json字符串,到时候你再parse一下
好的,谢谢,看样子 对于这种还是需要额外处理, 对象转成 string,然后 用zlib 压缩,然后客户端在解析到路子了。
动态对象一般都可以用数组来替代,不必转成字符串
repeated 要求 类型一样吧?而对象中 属性的类型也不一定完全 一样,比如 {1:{},2:null,....}这样好似不能用数组来确定吧?
@ 如果数组里面是对象的话,不是必要的属性就写成optional,这样里面的东西就要全部转成一个兼容的对象了。如果对象属性都差很多的话,放到数组里也不合适的吧,这样的js代码也会有性能问题的
可以的。你可以试试,我一直都是这么做的
谢谢,我再研究下。

我要回帖

更多关于 protobuf 复杂结构体 的文章

 

随机推荐