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. Unity3d 脚本使用规则

    脚本是Unity游戏开发的重要组成部分,通过脚本可以监听游戏中的相关事件和响应玩家的输入,并在游戏中安排事件发生.另外,脚本还可用于创建图形效果,控制对象的物理行为等.在Unity中使用脚本是需要注意 ...

  2. MVC5手工添加System.Web.Optimization

    VS2012web手工添辑一个空的mvC5的项目,添加EF6的支持,在别的项目里复制了母版页_Layout.cshtml过来,发现Styles.Render未引用,这个引用使用的命名空间是System ...

  3. 消息队列--RabbitMQ(一)

    1.消息队列概述 可以理解为保存消息的一个媒介/或者是个容器,与之相关有两个概念(即生产者(Publish)与消费者(Consumer)).所谓生产者,就是生产创造消息的一方,那么,消费者便是从队列中 ...

  4. PHP开源系统学习之fluxbb_1

    最近一直忙于做项目,虽说做了点新东西.感觉自己进步不是很大,总体水平还是跟半年前差不多,想到的东西跟以前差不多,写出来的东西也跟以前差不多.只是现在做的东西多些,比以前敢做了. 近期准备利用点时间,读 ...

  5. 洛谷P1800 software_NOI导刊2010提高(06)

    P1800 software_NOI导刊2010提高(06) 题目描述 一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术 ...

  6. 2017-10-5 清北刷题冲刺班a.m

    行列式 序列 #include<iostream> #include<cstdio> #define maxn 500010 using namespace std; int ...

  7. 洛谷P3396 哈希冲突(分块)

    传送门 题解在此,讲的蛮清楚的->这里 我就贴个代码 //minamoto #include<iostream> #include<cstdio> #include< ...

  8. bzoj4514: [Sdoi2016]数字配对(费用流)

    传送门 ps:费用流增广的时候费用和流量打反了……调了一个多小时 每个数只能参与一次配对,那么这就是一个匹配嘛 我们先把每个数分解质因数,记质因子总个数为$cnt_i$,那如果$a_i/a_j$是质数 ...

  9. oracle odbc连接sqlserver 无法查询字段

    最近因项目需要,需要在oracle数据库里面通过DBLINK方式链接SQLserver数据库(oracle 11G,Sqlserver2016,具体实现参考链接 http://blog.sina.co ...

  10. 消息中间件 | 消息协议 | MQTT3.1.1 -- 《分布式 消息中间件实践》笔记

    1999年,IBM和合作伙伴共同发明MQTT协议 14年,MQTT正式成为推荐的物联网传输协议标准 常应用于很多机器计算能力有限.底带宽.网络不可靠的远程通信应用场景中.   主要概念     MQT ...