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. lsnrctl start错误Linux Error: 29: Illegal seek (翻译:非法谋取)

    现在,想不起来为什么ORACLE的监听,怎么就突然无法起来了呢. 好吧,问题反正就是发生了. lsnrctl start 遇到如下错误, LSNRCTL for Linux: Version 10.2 ...

  2. 《Linux内核设计与实现》读书笔记(一)-内核简介

    本篇简单介绍内核相关的基本概念. 主要内容: 单内核和微内核 内核版本号 1. 单内核和微内核   原理 优势 劣势 单内核 整个内核都在一个大内核地址空间上运行. 1. 简单.2. 高效:所有内核都 ...

  3. 用SQL数据库做多表关联应怎样设计库结构20170527

    http://77857.blog.51cto.com/67857/143872/ 多表关联的话表之间必须得存在关系才行呢,这样建立外键约束就行了, 关系表中插入主表的主键做外键. 假设表1学生表st ...

  4. XML之DTD

    前言 上篇我们知道了,XML的应用范围还是很广的,那么无规矩不成方圆,如果我们每个人写XML的风格不一致,那么读起来是不是很费劲呢?所以格式良好的XML就渐渐的被我们所需要. 内容 格式良好指:拥有正 ...

  5. P1168 中位数(对顶堆)

    题意:维护一个序列,两种操作 1.插入一个数 2.输出中位数(若长度为偶数,输出中间两个较小的那个) 对顶堆 维护一个小根堆,一个大根堆,大根堆存1--mid,小根堆存mid+1---n 这样堆顶必有 ...

  6. Travelling (三进制+状压dp)

    题目链接 #include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read(){ ,f= ...

  7. return this链式操作

    function Fn(){}; Fn.prototype = { constructor:Fn, a:function(){ alert(1); return this; //实现链式操作.即fn. ...

  8. 4、python数据类型之列表(list)

    列表列表常见操作1.索引取值 name_list = ['wang','zhou','li','hu','wu','zhao'] print(name_list[0]) print(name_list ...

  9. 最小生成树(prim算法和kruskal算法)

    学习博客:https://www.cnblogs.com/zhangming-blog/p/5414514.html 其实就是加点法:从不属于这个集合的点中找从本集合可以找到的最小边,加入本集合 看代 ...

  10. vue简单的CheckBox节点树

    初学vue.js,恰好公司有个页面需要做一个简单的CheckBox组成的节点树,于是摸索着写了一个. 业务逻辑为:选中父节点,子节点全部选中:取消选中父节点,子节点全部取消:选中字节点,父节点选中. ...