您的位置:首页 > Web前端

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

2017-12-25 17:25 253 查看
 
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) {
  cout << "Enter person ID number: ";
  int id;
  cin >> id;
  person->set_id(id);
  cin.ignore(256,
'\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 !=
2) {
    cerr << "Usage:  " << argv[0] <<
" ADDRESS_BOOK_FILE" << endl;
    return -1;
  }

  tutorial::AddressBook address_book;

  {
    // Read the existing address book.
    fstream input(argv[1], ios::in | ios::binary);
    if (!input) {
      cout << argv[1] <<
": File not found.  Creating a new file." << endl;
    } else if (!address_book.ParseFromIstream(&input))
{
      cerr << "Failed to parse address book." << endl;
      return -1;
    }
  }

  // Add an address.
  PromptForAddress(address_book.add_people());

  {
    // Write the new address book back to disk.
    fstream output(argv[1], ios::out | ios::trunc
| ios::binary);
    if (!address_book.SerializeToOstream(&output))
{
      cerr << "Failed to write address book." << endl;
      return -1;
    }
  }

  // Optional:  Delete all global objects allocated by libprotobuf.
  google::protobuf::ShutdownProtobufLibrary();

  return 0;
}
 

读消息

#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 =
0; 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 =
0; 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 !=
2) {
    cerr << "Usage:  " << argv[0] <<
" ADDRESS_BOOK_FILE" << endl;
    return -1;
  }

  tutorial::AddressBook address_book;

  {
    // Read the existing address book.
    fstream input(argv[1], ios::in | ios::binary);
    if (!address_book.ParseFromIstream(&input))
{
      cerr << "Failed to parse address book." << endl;
      return -1;
    }
  }

  ListPeople(address_book);

  // Optional:  Delete all global objects allocated by libprotobuf.
  google::protobuf::ShutdownProtobufLibrary();

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

 

 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐