protobuf的简单的使用,不过还留下了一个问题,那就是之前主要介绍的都是对简单数据的赋值,简单数据直接采用set_xx()即可,但是如果不是简单变量而是自定义的复合类型变量,就没有简单的set函数调用了,下面看一个简单的例子。

在网络游戏中,游戏玩家之间的同步是一个最基本的功能,而同步是通过对坐标的广播进行的,因此我们假设一个简单的模型,当一个玩家的位置发生变化时,将玩家的新位置发给地图内所有玩家,根据这个情况写出以下proto文件。

  1. message PlayerPos
  2. {
  3. required  uint32  playerID = 1;
  4. required  float   posX = 2 ;
  5. required  float   posY = 3 ;
  6. };
  7. file  vector.protomessage  vector3D
  8. {
  9. required float x = 1;
  10. required float y = 2;
  11. required float z = 3;
  12. };

这样就有一个问题,现在的游戏都是3D游戏,因此需要xyz来表示位置,还需要另一组xyz来表示朝向,如果用简单变量的话就会显的很乱,而且无论是位置还是朝向其实都是一组xyz,因此可以将xyz抽出来成为一个复合数据类型,单独放在一个文件中。这样就构成以下文件。

  1. file  Player.protoimport "vector.proto";
  2. message PlayerPos
  3. {
  4. required uint32 playerID = 1;
  5. required vector3D  pos = 2;
  6. };

编译的时候先编译vector文件,采用import时需要注意路径,本例中两文件在同一目录下。

  1. protoc --cpp_out=.  vector.proto  Player.proto

proto对应的文件已经生成了,但是该怎么赋值呢,查API查了半天有点不知所以,干脆来看生成的类文件的源代码吧

  1. // required uint32 playerID = 1;
  2. inline bool has_playerid() const;
  3. inline void clear_playerid();
  4. static const int kPlayerIDFieldNumber = 1;
  5. inline ::google::protobuf::uint32 playerid() const;
  6. inline void set_playerid(::google::protobuf::uint32 value);
  7. // required .vector3D pos = 2;
  8. inline bool has_pos() const;
  9. inline void clear_pos();
  10. static const int kPosFieldNumber = 2;
  11. inline const ::vector3D& pos() const;
  12. inline ::vector3D* mutable_pos();
  13. inline ::vector3D* release_pos();
  14. inline void set_allocated_pos(::vector3D* pos);

上面列出了生成的部分源代码,主要是PlayerPos的操作变量的函数,第一个playID很简单,可以看到直接使用set_playerid ( ) 即可,但是对于嵌套的pos 发现没有对应的set_pos方法,不过发现了一个set_allocated_pos() 函数,这个函数也是set开头的,看看这个函数是干嘛的。

  1. inline void PlayerPos::set_allocated_pos(::vector3D* pos)
  2. {
  3. delete pos_;
  4. pos_ = pos;
  5. if (pos)
  6. {
  7. set_has_pos();
  8. }
  9. else {
  10. clear_has_pos();
  11. }
  12. }

看上去可以赋值,直接调用set_allocated_pos() 进行赋值看一看

  1. PlayerPos player;
  2. vector3D  tmp;
  3. tmp.x = 1;
  4. tmp.y = 2;
  5. tmp.z = 3;
  6. player.set_allocated_pos(&tmp)

编译没问题,但是运行时出现错误,而且是很奇怪的错误,仔细了查看一下PlayerPos的源码,发现一个问题

  1. ::vector3D* pos_;  ::google::protobuf::uint32 playerid_;

上面是PlayerPos中变量的保存形式,发现pos是作为一个指针存储的,如果按照之前的赋值 tmp 是一个局部变量,函数返回时局部变量自动销毁,而pos_保存的仍然是已被销毁的tmp的位置,因此会出错,如果采用new的话就可以解决这个问题,即赋值方法如下:

  1. PlayerPos player;vector3D  *tmp = new Vector3D;
  2. tmp->x = 1;
  3. tmp->y = 2;
  4. tmp->z = 3;
  5. player.set_allocated_pos(tmp)

这样即可,编译运行都没有问题。 
如此之外,还有一种赋值方法,就是调用mutable_pos()

  1. inline ::vector3D* PlayerPos::mutable_pos()
  2. {
  3. set_has_pos();
  4. if (pos_ == NULL)
  5. pos_ = new ::vector3D;
  6. return pos_;
  7. }

mutable_pos () 中自己new出了一个vector3D 对象,而vector3D中又实现了赋值的重载,因此可以这样解决:

    1. PlayerPos player;
    2. vector3D  *tmp = player.mutable_pos();
    3. tmp->x = 1;
    4. tmp->y = 2;
    5. tmp->z = 3;

protobuf 中的嵌套消息的使用 主要对set_allocated_和mutable_的使用的更多相关文章

  1. protobuf 中的嵌套消息的使用

    protobuf的简单的使用,不过还留下了一个问题,那就是之前主要介绍的都是对简单数据的赋值,简单数据直接采用set_xx()即可,但是如果不是简单变量而是自定义的复合类型变量,就没有简单的set函数 ...

  2. google protobuf 中的proto文件编写规则

    1. 简单介绍 protobuf文件:就是定义你要的消息(类似Java中的类)和消息中的各个字段及其数据类型(类似java类中的成员变量和他的数据类型) 2. Protobuf消息定义 消息由至少一个 ...

  3. protobuf中的编码规则

    protobuf中的编码规则 (1)序列化和反序列化: 在开始本部分的内容之前,首先有必要介绍两个基本概念,一个是序列化,一个是反序列化.这两个概念的定义在网上搜一下都很多的,但大多都讲得比较晦涩,不 ...

  4. 使用自己的Python函数处理Protobuf中的字符串编码

    我目前所在的项目是一个老项目,里面的字符串编码有点乱,数据库中有些是GB2312,有些是UTF8:代码中有些是GBK,有些是UTF8,代码中转来转去,经常是不太清楚当前这个字符串是什么编码,由于是老项 ...

  5. ZeroMQ接口函数之 :zmq_msg_recv - 从一个socket中接受一个消息帧

    ZeroMQ 官方地址 :http://api.zeromq.org/4-2:zmq_msg_recv zmq_msg_recv(3) ØMQ Manual - ØMQ/3.2.5 Name zmq_ ...

  6. 在WPF中处理Windows消息

    在Winform中 处理Windows消息通过重写WndProc方法 在WPF中 使用的是System.Windows. Sytem.Windows.Controls等名字空间,没有WndProc函数 ...

  7. 如何在项目中引入MetaQ消息收发机制

    当需要异步发送和接收大量消息时,需要在Crystal项目中引入MetaQ消息收发机制. 关于MetaQ使用的官方例子可参考:https://github.com/killme2008/Metamorp ...

  8. 【JS中循环嵌套常见的六大经典例题+六大图形题,你知道哪几个?】

    首先,了解一下循环嵌套的特点:外层循环转一次,内层循环转一圈. 在上一篇随笔中详细介绍了JS中的分支结构和循环结构,我们来简单的回顾一下For循环结构: 1.for循环有三个表达式,分别为: ①定义循 ...

  9. 微信小程序中发送模版消息注意事项

    在微信小程序中发送模版消息 参考微信公众平台Api文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/notice.html#模版消息管理 此参考地址 ...

随机推荐

  1. Spark机器学习之推荐引擎

    一. 最小二乘法建立模型 关于最小二乘法矩阵分解,我们可以参阅: 一.矩阵分解模型. 用户对物品的打分行为可以表示成一个评分矩阵A(m*n),表示m个用户对n各物品的打分情况.如下图所示: 其中,A( ...

  2. TouTiao开源项目 分析笔记1

    1.InitApp==>项目的入口Application 1.1.继承了MultiDexApplication 超过65K方法的APP,会遇到65535的错误.原因就是为了支持比较大型的APP而 ...

  3. cocos2d-x 3.0环境配置(转)

    cocos2d-x 3.0发布有一段时间了,作为一个初学者,我一直觉得cocos2d-x很坑.每个比较大的版本变动,都会有不一样的项目创建方式,每次的跨度都挺大…… 但是凭心而论,3.0RC版本开始 ...

  4. WIN8、WIN7访问Windows Server 2003服务器的数据库速度很慢、远程速度很慢的解决方法

    原因是微软在WIN7开始上加入了网络速度限制.在控制台执行以下命令即可解决: netsh interface tcp set global autotuninglevel=disabled

  5. 利用binlog server及Xtrabackup备份集来恢复误删表(drop)

      Preface       Today I'm gonna test how to rescue a dropped table from binlog server based on a ful ...

  6. time模块与random模块,六位含字母随机验证码

    # time模块# import time# time.time()#计算这一时刻时间戳 *******# time.sleep(1)#让cpu休眠一定时间 *******# time.clock() ...

  7. day04_08-while查询所有行

    <?php $link = @mysql_connect('localhost','root',''); mysql_query('use test',$link); mysql_query(' ...

  8. 深入理解net core中的依赖注入、Singleton、Scoped、Transient(四)【转】

    原文链接:https://www.cnblogs.com/gdsblog/p/8465401.html 相关文章: 深入理解net core中的依赖注入.Singleton.Scoped.Transi ...

  9. Nginx下配置codeigniter框架

    原来在winserver+Apache环境下工作良好的一个微信公众号后台迁移到阿里云(环境:Ubuntu 64位 | PHP5.4 | Nginx1.6)下却频出 404,403,只能访问CI rou ...

  10. maven中mapper.xml不发布的问题

    在自定义的包中定义了mapper.xml然后利用mybatis的扫描包形式来动态创建mapper 开启工程报错: 说无效的绑定 原因: 发布的war中,工程包中的mapper根本就没有出现在class ...