use protocol buffers

use protocol buffers

Why using Protocol Buffers

We are going to use the example of a very simple "address book" application, contact details can be read from the file. Everyone in the address book has a name, ID, email address and telephone number.

How to serialize and retrieve structured data? There are several solutions:

  • Transmission / reception data structure of the native memory in binary form. Typically, this is a fragile method, since the receiving / reading the code to be compiled based on the same memory layout, the size of the end environment. Meanwhile, when the file increases, along with the original format of the data will be associated with the format and the rapid spread of software, which makes it difficult to extend the file format.
  • You can create an ad-hoc method, encoded as a string of data items - such as the encoding 4 integers 12:3:-23:67. Although it need to write a one-time decoding and encoding and decoding of code takes a little run-time cost, but this is a simple and flexible way. This is most suitable coding very simple data.
  • Serialize the data to XML. This method is very attractive, because XML is a format suitable for people to read, and many promising language development library. If you want to share data with other programs and projects, this might be a good choice. However, we all know, XML is space intensive, and at the time of encoding and decoding, its program will cause huge performance penalty. At the same time, the use of XML DOM tree is considered more complex than a simple field operation of a class.

Protocol buffers to this problem is a flexible, efficient, automated solution. Use Protocol buffers, you need to write a .protodescription used to describe the data structure stored what you want. Using the .protofile, protocol buffer compiler can create a class that implements protocol buffer data for efficient automation binary format encoding and decoding. Class provides the generated getters and setters field configuration protocol buffer, and as a means to read and write the details of the protocol buffer. It is important, protocol buffer format support expanded format, the code can still read the old format encoded data.

Installation:
https://github.com/protocolbuffers/protobuf/blob/master/src/README.md

.Proto source code files:

// [START declaration]
syntax = "proto3";
package tutorial;

import "google/protobuf/timestamp.proto";
// [END declaration]
 
// [START messages]
message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
  google.protobuf.Timestamp last_updated = 5;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}
// [END messages]

Here, we have a simple explanation of the syntax used .proto file.

1) protobuf .proto file used to start a package declaration, namespace declaration and the corresponding package in C ++, the messages defined in a package statement will appear in the corresponding namespace namespace. import statement for introducing other .proto message definition file, thus defining a plurality .proto message file and then use the association.

2) Then, you need to define the message structure. A message comprising a plurality of belt type member. There are many standard protobuf simple data types, including bool, int32, float, double, and String, protobuf comes .proto file also has some defined message structure, for example, appears above google.protobuf.Timestamp. Of course, you can according to these types, other messages further configured, such as the above PhoneNumber message contains Person, Person message containing the AddressBook. You can also define the type of messages in other messages, such as defined above appear in Person in PhoneNUmber. You can also define enum types, such as the above PhoneType, comprising three optional values ​​MOBILE, HOME and WORK.

"= 1", "2 =" in binary code is used to identify the corresponding tag field. Only one byte tag encoded in the range of 1-15, and a larger number required to encode two byte, so for those used in the field, can use the tag in the range of 1-15.

In addition, each tag may be modified using the modifier as follows:

(1) singular: indicates that the field can have one, you do not. If not, the coding, it does not take up space.

(2) repeated: This field indicates repeated 0 times or more, the value of this field will be coded in order.

  1. .Proto over the definition file, the next step is to compile the proto file, we assume that this proto file named addressbook.proto. To compile the file, run the following statement:
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/address.proto

-I specify the location where the file is located proto, $ DST_DIR specify the location of the generated files are located, here --cpp_out representation generation document as C ++ files, build directory in $ DST_DIR, $ SRC_DIR / addressbook.proto.

If you call the above command is located in the proto file, it can be abbreviated as follows:

protoc --cpp_out=. addressbook.proto

Call the above command file, generated for addressbook.pb.h and addressbook.pb.cc. Presumably, for xxx.proto, generated files should xxx.pb.h and xxx.pb.cc.

Made pb file formats:

#include <ctime>
#include <fstream>
#include <google/protobuf/util/time_util.h>
#include <iostream>
#include <string>

#include "addressbook.pb.h"

using namespace std;

using google::protobuf::util::TimeUtil;

// 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;
    }
  }
  *person->mutable_last_updated() = TimeUtil::SecondsToTimestamp(time(NULL));
}

// 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;
}

Pb parsing file

#include <fstream>
#include <google/protobuf/util/time_util.h>
#include <iostream>
#include <string>

#include "addressbook.pb.h"

using namespace std;

using google::protobuf::util::TimeUtil;

// 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.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;
        default:
          cout << "  Unknown phone #: ";
          break;
      }
      cout << phone_number.number() << endl;
    }
    if (person.has_last_updated()) {
      cout << "  Updated: " << TimeUtil::ToString(person.last_updated()) << 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;
}

Excuting an order: 

$ g++ addressbook.pb.cc write.cpp -o write `pkg-config --cflags --libs protobuf`

Usage of the command pkg-config: https://blog.csdn.net/luotuo44/article/details/24836901

  • --cflags: [equivalent to] -I (uppercase i) property
  • --libs: -L equivalent [] and [] -l (lowercase L) properties

pkg-config pile compile-time parameters can be omitted

c / c ++ mutual learning QQ group: 877 684 253

I micro letter: xiaoshitou5854

Guess you like

Origin www.cnblogs.com/xiaoshiwang/p/11578426.html