Protocol Buffer学习教程之类库应用(四)

此教程是通过一个简单的示例,给C++开发者介绍一下如何使用protocol buffers编程,主要包括以下几部分:

定义一个.proto文件

如何使用protocol buffer编译器生成C++类文件

如何使用Protocol buffer api读写消息

这并不是分全面的protocol buffer的C++编程手册,更详尽的资料请参见Protocol Buffer Language Guide(https://developers.google.com/protocol-buffers/docs/proto), the C++ API Reference (https://developers.google.com/protocol-buffers/docs/reference/cpp/index.html), the C++ Generated Code Guide (https://developers.google.com/protocol-buffers/docs/reference/cpp-generated), 和the Encoding Reference (https://developers.google.com/protocol-buffers/docs/encoding)

定义一个.proto文件

创建一个文本文件,重命名为“addressbook.proto”,注意扩展名为“.proto”。

syntax = "proto2";

package tutorial;

message Person {

required string name = 1;

required int32 id = 2;

optional string email = 3;

enum PhoneType {

MOBILE = 0;

HOME = 1;

WORK = 2;

}

message PhoneNumber {

required string number = 1;

optional PhoneType type = 2 [default = HOME];

}

repeated PhoneNumber phones = 4;

}

message AddressBook {

repeated Person people = 1;

}

生成类文件

然后通过前面第三部份介绍生成的proto.exe编译器,生成C++类文件,在命令行中,cd到proto.exe根目录,执行以下命令:

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

然后将生成两个文件addressbook.pb.h和addressbook.pb.cc。打开头文件,能看到以下内容:

// name
  inline bool has_name()
const;
  inline void clear_name();
  inline const ::std::string&
name() const;
  inline void set_name(const ::std::string&
value);
  inline void set_name(const char*
value);
  inline ::std::string* mutable_name();

// id
  inline bool has_id()
const;
  inline void clear_id();
  inline int32_t id()
const;
  inline void set_id(int32_t value);

// email
  inline bool has_email()
const;
  inline void clear_email();
  inline const ::std::string&
email() const;
  inline void set_email(const ::std::string&
value);
  inline void set_email(const char*
value);
  inline ::std::string* mutable_email();

// phones
  inline int phones_size()
const;
  inline void clear_phones();
  inline const ::google::protobuf::RepeatedPtrField<
::tutorial::Person_PhoneNumber >& phones()
const;
  inline ::google::protobuf::RepeatedPtrField<
::tutorial::Person_PhoneNumber >* mutable_phones();
  inline const ::tutorial::Person_PhoneNumber&
phones(int index)
const;
  inline ::tutorial::Person_PhoneNumber* mutable_phones(int index);
  inline ::tutorial::Person_PhoneNumber* add_phones();

方法分析

可以看到,每个段都有读、写方法,读方法就是段名,没有加前后缀,而写方法以set_前缀开头,可能有多个对应不同的设置方式,同时还有清空clear_前缀的方法,has_前缀的方法是用于判断某个段是否存在,即赋过值。而mutable_前缀的方法,是直接给返回对象的指针。

对于repeated字段,会发现有更多的接口,repeated字段相当于队列数据,里面存储的是同一类型的数据。

_size后缀的方法,用于统计队列里的元素数量。

同时提供直接通过index索引来读、写元素的方法,段名加元素索引的方法进行读写。写通过索引,返回对应元素的指针,然后通过指针对元素进行修改操作。

还有一个add_前缀方法,这个方法相当于给当前队列增加一个元素空间,它返回新增的元素空间的指针。可以通过此指针对它进行赋值操作。

标准方法

bool IsInitialized() const;检验是否必须赋值的段都赋值了。

string DebugString() const;返回一个对于消息可读的描述,对于调试非常有用。

void CopyFrom(const Person& from);从提供的消息对象复制一个副本。

void Clear();清空消息中的所有段到空的状态。

序列化与反序列化

bool SerializeToString(string* output) const;序列化消息并以字节流的方式存储到string类型的output中,它是二进制的,并不是text文本,使用string类只是为了方便。

bool ParseFromString(const string& data);对提供的data数据进行序列化成消息对象。

bool SerializeToOstream(ostream* output) const;反序列化成C++的流

bool ParseFromIstream(istream* input);把流序列化成消息对象。

填充消息

#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;

// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person*
person) {,
'\n');

cout << "Enter name: ";
  getline(cin, *person->mutable_name());

cout << "Enter email address (blank for none): ";
  string email;
  getline(cin, email);
  if (!email.empty()) {
    person->set_email(email);
  }

while (true) {
    cout << "Enter a phone number (or leave blank to finish): ";
    string number;
    getline(cin, number);
    if (number.empty()) {
      break;
    }

tutorial::Person::PhoneNumber*
phone_number = person->add_phones();

    phone_number->set_number(number);

cout << "Is this a mobile, home, or work phone? ";
    string type;
    getline(cin, type);
    if (type ==
"mobile") {
      phone_number->set_type(tutorial::Person::MOBILE);
    } else if (type ==
"home") {
      phone_number->set_type(tutorial::Person::HOME);
    } else if (type ==
"work") {
      phone_number->set_type(tutorial::Person::WORK);
    } else {
      cout << "Unknown phone type.  Using default." << endl;
    }
  }
}

// Main function:  Reads the entire address book from a file,
//   adds one person based on user input, then writes it back out to the same
//   file.
int main(int argc,
char* argv[]) {
  // Verify that the version of the library that we linked against is
  // compatible with the version of the headers we compiled against.
  GOOGLE_PROTOBUF_VERIFY_VERSION;

if (argc !=
] <<
] <<
": File not found.  Creating a new file." << endl;
    } else if (!address_book.ParseFromIstream(&input))
{], ios::out | ios::trunc
| ios::binary);
    if (!address_book.SerializeToOstream(&output))
{;
}

读消息

#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;

// Iterates though all people in the AddressBook and prints info about them.
void ListPeople(const tutorial::AddressBook&
address_book
) {
  for (int i =
; i <
address_book.people_size(); i++) {
    const tutorial::Person& person = address_book.people(i);

cout << "Person ID: " <<
person.id() << endl;
    cout << "  Name: " <<
person.name() << endl;
    if (person.has_email()) {
      cout << "  E-mail address: " <<
person.email() << endl;
    }

for (int j =
; j <
person.phones_size(); j++) {
      const tutorial::Person::PhoneNumber&
phone_number = person.phones(j)
;

switch (phone_number.type())
{
        case tutorial::Person::MOBILE:
          cout << "  Mobile phone #: ";
          break;
        case tutorial::Person::HOME:
          cout << "  Home phone #: ";
          break;
        case tutorial::Person::WORK:
          cout << "  Work phone #: ";
          break;
      }
      cout << phone_number.number() << endl;
    }
  }
}

// Main function:  Reads the entire address book from a file and prints all
//   the information inside.
int main(int argc,
char* argv[]) {
  // Verify that the version of the library that we linked against is
  // compatible with the version of the headers we compiled against.
  GOOGLE_PROTOBUF_VERIFY_VERSION;

if (argc !=
] <<
], ios::in | ios::binary);
    if (!address_book.ParseFromIstream(&input))
{;
}

关于完整的API接口说明,请查看:https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.message#MessageFactory

Protocol Buffer学习教程之类库应用(四)的更多相关文章

  1. Protocol Buffer学习教程之编译器与类文件(三)

    Protocol Buffer学习教程之编译器与类文件(三) 1. 概述 在前面两篇中,介绍了Protobuf的基本概念.应用场景.与protobuf的语法等.在此篇中将介绍如何自己编译protobu ...

  2. Protocol Buffer学习教程之开篇概述(一)

    1. Protocol Buffer是什么 Protocol Buffer是google旗下的产品,用于序列化与反序列化数据结构,但是比xml更小.更快.更简单,而且能跨语言.跨平台.你可以把你的数据 ...

  3. Protocol Buffer学习教程之语法手册(二)

    1.说明 此向导介绍如何使用protocol buffer language创建一个自己的protocolbuffer文件,包括语法与如何通过“.proto”文件生成数据访问的类,此处只介绍proto ...

  4. Protocol Buffers学习教程

    最近看公司代码的过程中,看到了很多proto后缀的文件,这是个啥玩意?问了大佬,原来这是Protocol Buffers! 这玩意是干啥的?查完资料才知道,又是谷歌大佬推的开源组件,这玩意完全可以取代 ...

  5. Protocol Buffer学习笔记

    Protocol Buffer Protobuf基础概念 Protobuf是google开发的数据结构描述语言,能够将结构化数据序列化与反序列化,取代json和xml,常用于服务器通信协议.RPC系统 ...

  6. google protocol buffer的原理和使用(四)

    有个电子商务的系统(如果用C++实现).当中的模块A须要发送大量的订单信息给模块B.通讯的方式使用socket. 如果订单包含例如以下属性: ----------------------------- ...

  7. 学习Google Protocol buffer之语法

    上一篇结尾的时候问了几个问题,其实主要就是这个protoBuffer协议的语法,弄清楚语法后边才好开展工作嘛,不然大眼而对小眼儿,互相不认识,就没法玩耍了.其实就是学习怎么用google提供的这套 p ...

  8. netty4与protocol buffer结合简易教程

    各项目之间通常使用二进制进行通讯,占用带宽小.处理速度快~ 感谢netty作者Trustin Lee.让netty天生支持protocol buffer. 本实例使用netty4+protobuf-2 ...

  9. 【神经网络与深度学习】Google Protocol Buffer介绍

    简介 什么是 Google Protocol Buffer? 假如您在网上搜索,应该会得到类似这样的文字介绍: Google Protocol Buffer( 简称 Protobuf) 是 Googl ...

随机推荐

  1. EF Code first 和 DDD (领域驱动设计研究)系列一

    在上个公司工作时,开发公司产品的过程中,接触到了EF Code first. 当时,整个产品的架构都是Lead developer设计建立的,自己也不是特别理解,就赶鸭子上架跟着一起开发了. 现在回过 ...

  2. Improved RGB-D-T based Face Recognition 论文笔记

    本文将基于深度学习的卷积神经网络(CNN)应用于基于RGB-D-T的多模态人脸识别问题. 此外,引入了基于CNN的识别模块与各种纹理特征(LBP,HOG,HAAR,HOGOM)的后期融合,在基准RGB ...

  3. CSS概念 - 可视化格式模型(一) 盒模型与外边距叠加

    可以参考<精通CSS 高级WEB标准解决方案>第三章. 可视化格式模型 可视化格式模型要掌握的3个最重要的CSS概念是 浮动.定位.盒模型. 这些概念控制在页面上安排和显示元素的方式, 形 ...

  4. webpack@3.6.0(4) -- 配置模块化开发

    本篇内容 watch 版权插件 hash.chunkhash.contenthash的区别 watch 修改文件时自动打包 webpack --watch //webpack.config.js,与d ...

  5. 不重新编译安装php模块的方法

    如果你有下面两种经历: 如果php通过源码安装(php7),如果后来需要开启某个自带模块(例如ldap,snmp等),通常需要重新编译. 另外一些安装php模块的经历,例如redis,swoole,y ...

  6. cf873F(xjb+二分)

    题目链接:http://codeforces.com/problemset/problem/837/F 题意:给出一个大小为 n 的数组 a 和一个数 k,每次操作后的到一个 a' 数组,a'i 为 ...

  7. mysql安装等操作

    CentOS 6.5系统中安装配置MySQL数据库 卸载掉原有mysql rpm -qa | grep mysql // 这个命令就会查看该操作系统上是否已经安装了mysql数据库 rpm -e my ...

  8. CTS/APIO2019游记

    退役后游记... 这次是真·游记了 ghj1222自从省选翻车后心情一直不错 5.12 (CTS 报到) 没去thupc(话说都不知道thupc这时候举行),于是就这天从衡水出发了 翻来覆去睡不着觉, ...

  9. Jdk升级到11引起的问题:程序包javax.xml.bind.annotation不存在

    Jdk12 都发布了, 我也下载一个玩一玩吧.刚准备要下载,发现之前已经下载了一个11, 那就11 吧,也不用太新了. 安装了jdk11,习惯性的设置了一下环境变量: JAVA_HOME=D:\too ...

  10. JS对DOM节点操作整理

    获取节点: //按照ID获取 document.getElementById('element'); //按照节点名称获取,返回类数组对象 document.getElementsByTagName( ...