C + + Protobuffer use of detailed

Source: Internet
Author: User
Tags serialization


One, why use protocol Buffer?

Before answering this question, let's first give a system scenario that is often encountered in actual development. For example, our client programs are developed using Java and may run from different platforms, such as Linux, Windows, or Android, and our server programs are usually based on Linux and are developed using C + +. There are several ways to design message formats for data communication between these two programs, such as:
1. Direct transfer of a byte-aligned structure in C/A + + language data, as long as the structure of the declaration is a fixed-length format, then this method is very convenient for C + + programs, only need to be received in accordance with the structure of the type of data forced conversion. In fact, the variable length structure is not very troublesome. When sending data, you only need to define a struct variable and set the value of each member variable, and then send the binary data to the remote char*. Conversely, this approach can be very cumbersome for Java developers, first you need to save the received data in Bytebuffer, and then read each field one by one according to the agreed byte order, and then assign the read value to the field variable in the other value object, so that other code logic in the program can be written. For this type of program, the benchmark is that both the client and the server must complete the message Message Builder before they can be expanded, and the design method will directly lead to slow development of the Java program. Even in the debug phase, you will often encounter small errors in a variety of field field stitching in Java programs.
2. Using the SOAP Protocol (WebService) as a format carrier for message messages, messages generated by this method are text-based and have a large amount of XML descriptive information, which will greatly increase the burden of network IO. And because of the complexity of XML parsing, this can also greatly reduce the performance of message parsing. In short, using this design method will make the overall performance of the system significantly reduced.
For the above two ways of the problem, Protocol buffer can be a good solution, not only that, Protocol buffer also has a very important advantage is to ensure the same message messages between the old and new versions of compatibility. As for the specific way we will be given in the following blog.

Defines a protocol buffer message

Working with instances

Define a Addressbook.proto
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 phone = 4;
}
Message AddressBook {
Repeated person person = 1;
}

Detail explanation
1, package declaration in order to prevent the naming conflicts between different projects, the tutorial here is equivalent to namespace.

2. Message is a collection that contains several types of fields, and you can use bool, Int32, float, double, and string types. You can embed a message collection, similar to struct.

3, "= 1", "2" notation identifies the unique tag of the Type field in the binary encoding, representing the placement of the different fields in the serialized binary data.

Tag number 1-15 is less than a byte compared to higher numbers, so you can use 1-15 of the tag as commonly used repeated elements,16 or higher tag to leave Less-commonly Use left to optional elements.

4, each field must use the following identifiers

Required: Field value must be provided, otherwise the message will be considered uninitialized.
Optional: Field value optional
Repeated: The field may be repeated any number of times (including 0). You can consider the repeated field as a dynamic size array.
5. Enum is the keyword of the enumeration type definition, 0 and 1 represent the actual integer value corresponding to the enumeration value, and as C + +, you can specify any integer value for the enumeration value without always starting with the definition of 0.

6, you can define multiple messages in the same. proto file so that you can easily implement the definition of a nested message. Protocol Buffer provides another import of the keyword so that we can define many common messages in the same. proto file, while other message definition files can include the messages defined in the file by import, such as:

Import "Myproject/commonmessages.proto"

Basic rules for qualifiers (required/optional/repeated)
1. At least one required type of field must be left in each message.

2, each message can contain 0 or more optional types of fields.

3, the field represented by repeated can contain 0 or more data.

4. If you intend to add a new field to the original message protocol and ensure that the old version of the program is read or written correctly, the newly added field must be optional or repeated. The reason is very simple, the old version of the program can not read or write the new required qualifier field.

Protocol Buffer Message Upgrade principle
1, do not modify the existing field of the label number.

2. Any newly added fields must be optional and repeated qualifiers, otherwise there is no guarantee of message compatibility between new and old programs when passing messages to each other.

3, in the original message, can not remove the existing required field, optional and repeated type of fields can be removed, but they used before the tag number must be retained, cannot be reused by new fields.

4, Int32, UInt32, Int64, UInt64 and bool are compatible between types, Sint32 and Sint64 are compatible, string and bytes are compatible, FIXED32 and SFIXED32, and FIXED64 and SFIXED64 are compatible, which means that if you want to modify the type of an existing field, you can only modify it to be compatible with its original type to ensure compatibility, otherwise you will break the compatibility of the old and new message formats.

5, optional and repeated qualifiers are also mutually compatible.

Compile your protocol buffers.

Compilation method

protoc-i= $SRC _dir--cpp_out= $DST _dir $SRC _dir/addressbook.proto
Note: $SRC _dir is source directory, $DST _dir directory, destination directory will have the following two files after compiling

Addressbook.pb.h: Header file, declaring the generated class
Addressbook.pb.cc:cpp file to implement the generated class.
Protobuffer API

After compiling we can get the following message API functions


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 ();
Phone
inline int phone_size () const;
inline void Clear_phone ();
Inline const:: Google::p rotobuf::repeatedptrfield<:: Tutorial::P erson_phonenumber >& phone () const;
Inline:: Google::p rotobuf::repeatedptrfield<:: Tutorial::P erson_phonenumber >* mutable_phone ();
Inline Const:: Tutorial::P erson_phonenumber& Phone (int index) const;
Inline:: Tutorial::P erson_phonenumber* mutable_phone (int index);
Inline:: Tutorial::P erson_phonenumber* add_phone ();

Standard Message method

Each message contains a series of other methods that allow you to check or manipulate the entire message:


BOOL isinitialized () const; Check if all required field is set
String debugstring () const; Returns a readable description of the message that is useful for debugging
void CopyFrom (const & from); Overrides the message with the given message value
void Clear (); Empty all elements to empty state
Use your protocbuffer.
Parsing and serialization (parsing and serialization)
Each protocol buffer class has several functions that can use the protocol buffer binary format to write and read the information you choose.


BOOL Serializetostring (String * output) const; Serializes the "message" and stores the bytes in the given string. Note This bytes are binary, not text; We use the string class as a convenient container.
BOOL Parsefromstring (const string & data); Parses a message from the given string.
BOOL Serializetoostream (OSTREAM * output) const; Writes the message to the given C + + Ostream.
BOOL Parsefromistream (istream * input); Parses a message from the given C + + istream.
Writing A Message

#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::P erson* 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::P erson::P honenumber* phone_number = Person->add_phone ();
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::P erson::mobile);
}
else if (type = = "Home") {
Phone_number->set_type (Tutorial::P erson::home);
}
else if (type = = "Work") {
Phone_number->set_type (Tutorial::P erson::work);
}
else {
cout << "Unknown phone type. Using default. "<< Endl;
}
}
}
Main function:reads The entire address book from a file,
Adds one person based in user input, then writes it back out to the same
File.
int main (int argc, char * argv []) {
Verify that version of the library so 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_person ());
{
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::p rotobuf::shutdownprotobuflibrary ();
return 0;
}
Reading A Message


#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.person_size (); i + +) {
Const Tutorial::P erson& person = Address_book.person (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.phone_size (); j + +) {
Const Tutorial::P erson::P honenumber& phone_number = Person.phone (j);
Switch (Phone_number.type ()) {
Case Tutorial::P erson::mobile:
cout << "Mobile phone #:";
Break
Case Tutorial::P erson::home:
cout << "Home phone #:";
Break
Case Tutorial::P erson::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 version of the library so 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::p rotobuf::shutdownprotobuflibrary ();
return 0;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.