Protocol Buffer Technology Deep Understanding (C + + instance) _c language

Source: Internet
Author: User
Tags object serialization
This blog is still based on Google's official document as the main line, the code example is completely taken from a demo project we are developing, through a period of previous attempts, the feeling that this combination of ways is more conducive to training and internal technical exchange. Or the words, there is no best, only the most suitable. I want to write a blog is also this reason, different technical topics may need to adopt a different style. Well, let's cut to the chase as soon as possible.

first, generate target language code
The following command helps us compile a set of protocol buffer-formatted messages defined in the Mymessage.proto file into the target language (c + +) code. As for the contents of the message, we will list them in the form of a fragment later, and all the source code will be given in the attachment.
Copy Code code as follows:

Protoc-i=./message--cpp_out=./src./mymessage.proto

As you can see from the command line arguments above, the file to be compiled is Mymessage.proto, and he is stored in the message subdirectory of the current directory. The--cpp_out parameter indicates that the compilation tool we need to generate the target language is C + +, and the output directory is the SRC subdirectory of the current directory. In this case, the generated target code file name is Mymessage.pb.h and MyMessage.pb.cc.

ii. C + + code generated by simple message
Here we first define the simplest message, which contains only the fields of the original type.
Copy Code code as follows:

Option optimize_for = Lite_runtime;
Message Logonreqmessage {
Required Int64 Acctid = 1;
Required String passwd = 2;
}

Because the value of the option Optimize_for defined in the Mymessage file is Lite_runtime, the parent classes of all C + + classes generated by the. Proto file are:: Google::p rotobuf::messagelite, not: : Google::p rotobuf::message. In the previous blog has given some brief explanation, the Messagelite class is the message's parent class, in Messagelite will be missing protocol buffer to reflect the support, but this kind of function in the message class provides the concrete implementation. For our project, the entire system is relatively closed, does not interact with more external programs, while our client part is running on the Android platform, in view of this, we consider using the Lite version of Protocol Buffer. This will not only result in higher coding efficiency, but also less resources to be compiled by the generated code, and the flexibility and scalability of reflection can be completely ignored for this project. Let's take a look at some of the C + + class declarations generated by message logonreqmessage, as well as descriptive comments on common methods.
Copy Code code as follows:

Class Logonreqmessage:public:: Google::p rotobuf::messagelite {
Public
Logonreqmessage ();
Virtual ~logonreqmessage ();
Implements message----------------------------------------------
The following member functions implement virtual functions from Messagelite.
Creates a new Logonreqmessage object that is equivalent to clone.
logonreqmessage* New () const;
Initializes the current object with a different Logonreqmessage object, equivalent to an assignment operator overload (operator=)
void CopyFrom (const logonreqmessage& from);
Clears all data in the current object, placing all member variables in an uninitialized state.
void Clear ();
Determines whether the current state has been initialized.
BOOL isinitialized () const;
After assigning all the variables of the current object, gets the number of bytes required after the object is serialized.
int bytesize () const;
Gets the type name of the current object.
:: std::string gettypename () const;
Required Int64 Acctid = 1;
The following member functions are generated because of the Acctid field defined in the message.
This static member represents the label value of the Acctid. The naming rule is K + FieldName (Hump rule) + FieldNumber.
static const int kacctidfieldnumber = 1;
False if the Acctid field has been set to return true.
inline bool Has_acctid () const;
The Has_acctid function returns false after the function is executed, and the following Acctid function returns the default value of Acctid.
inline void Clear_acctid ();
Returns the current value of the Acctid field and returns the default value of the int64 type if there is no setting.
Inline:: Google::p rotobuf::int64 acctid () const;
Sets a new value for the Acctid field, and the Has_acctid function returns True after the function is called.
inline void Set_acctid (:: Google::p rotobuf::int64 value);
Required String passwd = 2;
The following member functions are generated because of the passwd field defined in the message. The function generated here and the above Acctid
The set of functions that are generated are basically similar. So here's just a list of differences.
static const int kpasswdfieldnumber = 2;
inline bool has_passwd () const;
inline void clear_passwd ();
Inline const::std::string& passwd () const;
inline void set_passwd (const::std::string& value);
Sets the variable value for the const char* type for a String type field.
inline void set_passwd (const char* value);
inline void set_passwd (const char* value, size_t size);
You can assign a value directly to a passwd object by returning a value. HAS_PASSWD returns True after the function is called.
Inline:: std::string* mutable_passwd ();
Releases the current object's ownership of the passwd field and returns the Passwd Field object pointer. After this function is called, the passwd Field object
Ownership will be handed over to the caller. False is returned after the HAS_PASSWD function is called again.
Inline:: std::string* release_passwd ();
Private
... ...
};

Here is the C + + test code and descriptive comment for the read-write Logonreqmessage object.
Copy Code code as follows:

void Testsimplemessage ()
{
printf ("==================this is simple message.================\n");
Serializes the Logonreqmessage object to the specified memory area.
Logonreqmessage Logonreq;
Logonreq.set_acctid (20);
LOGONREQ.SET_PASSWD ("Hello World");
Gets the space occupied by the object serialization ahead of time and makes a one-time allocation to avoid multiple allocations
resulting in performance overhead. In this way, the serialized data can also be encrypted.
Then it is persisted or sent to the remote end.
int length = Logonreq.bytesize ();
char* buf = new Char[length];
Logonreq.serializetoarray (buf,length);
Reads and deserializes the Logonreqmessage object from memory while printing the results.
Logonreqmessage LOGONREQ2;
Logonreq2.parsefromarray (buf,length);
printf ("Acctid =%i64d, password =%s\n", Logonreq2.acctid (), logonreq2.passwd (). C_STR ());
delete [] buf;
}

C + + code generated by nested message
Enum UserStatus {
OFFLINE = 0;
ONLINE = 1;
}
Enum Loginresult {
logon_result_success = 0;
Logon_result_notexist = 1;
LOGON_RESULT_ERROR_PASSWD = 2;
Logon_result_already_logon = 3;
Logon_result_server_error = 4;
}
Message UserInfo {
Required Int64 Acctid = 1;
Required String name = 2;
Required UserStatus status = 3;
}
Message Logonrespmessage {
Required Loginresult Logonresult = 1;
Required UserInfo UserInfo = 2; A userinfo message is nested here.
}
For the C + + code generated by the above message, UserInfo is not much different from the logonreqmessage in the previous example because it only contains the original Type field, and is not listed here. Because the UserInfo type of field is nested in the logonrespmessage message, here we will just give the C + + code and critical annotations generated by the message.
Copy Code code as follows:

Class Logonrespmessage:public:: Google::p rotobuf::messagelite {
Public
Logonrespmessage ();
Virtual ~logonrespmessage ();
Implements message----------------------------------------------
...//This part of the function is the same as the previous example.
Required. Loginresult Logonresult = 1;
The following member functions are generated because of the Logonresult field defined in the message.
This is essentially the same as the previous example, except that the type changed to an enumeration type Loginresult.
static const int klogonresultfieldnumber = 1;
inline bool Has_logonresult () const;
inline void Clear_logonresult ();
Inline Loginresult logonresult () const;
inline void Set_logonresult (loginresult value);
Required. UserInfo UserInfo = 2;
The following member functions are generated because of the UserInfo field defined in the message.
This is just the part that lists the differences between the and non-message type fields.
static const int kuserinfofieldnumber = 2;
inline bool Has_userinfo () const;
inline void Clear_userinfo ();
Inline const::userinfo& UserInfo () const;
You can see that the class does not generate the Set_userinfo function for setting up and modifying the UserInfo field, but rather the work
Handed the following Mutable_userinfo function. So every time the function is invoked, Protocol buffer will assume that
The value of this field has been set, and the Has_userinfo function will return true. In the actual code, we can
This function returns an internal pointer to the UserInfo field and completes initialization of the UserInfo member variable based on the pointer.
Inline:: userinfo* mutable_userinfo ();
Inline:: userinfo* release_userinfo ();
Private
... ...
};

Here is the C + + test code and descriptive comment for the read-write Logonrespmessage object.
Copy Code code as follows:

void Testnestedmessage ()
{
printf ("==================this is nested message.================\n");
Logonrespmessage Logonresp;
Logonresp.set_logonresult (logon_result_success);
As described above, the pointer to the UserInfo field is returned through the Mutable_userinfo function, and then the object pointer is initialized.
userinfo* UserInfo = Logonresp.mutable_userinfo ();
Userinfo->set_acctid (200);
Userinfo->set_name ("Tester");
Userinfo->set_status (OFFLINE);
int length = Logonresp.bytesize ();
char* buf = new Char[length];
Logonresp.serializetoarray (buf,length);
Logonrespmessage logonResp2;
Logonresp2.parsefromarray (buf,length);
printf ("Logonresult =%d, Userinfo->acctid =%i64d, Userinfo->name =%s, Userinfo->status =%d\n"
, Logonresp2.logonresult (), Logonresp2.userinfo (). Acctid (), Logonresp2.userinfo (). Name (). C_STR (), Logonresp2.userinfo (). status ());
delete [] buf;
}

iv. C + + code generated by repeated nested message
Message Buddyinfo {
Required UserInfo UserInfo = 1;
Required Int32 GroupID = 2;
}
Message Retrievebuddiesresp {
Required Int32 buddiescnt = 1;
Repeated buddyinfo buddiesinfo = 2;
}
For the code generated by the above message, we will only elaborate on the C + + code corresponding to the RETRIEVEBUDDIESRESP message, the remainder is basically the same as the example in the previous section, and can be directly referenced. And for the code in the Retrievebuddiesresp class, we simply explain the code generated by the Buddiesinfo field in more detail.
Copy Code code as follows:

Class Retrievebuddiesresp:public:: Google::p rotobuf::messagelite {
Public
Retrievebuddiesresp ();
Virtual ~retrievebuddiesresp ();
...//The rest of the code's functional annotations can refer to the previous example.
Repeated. Buddyinfo buddiesinfo = 2;
static const int kbuddiesinfofieldnumber = 2;
Returns the number of members in an array.
inline int buddiesinfo_size () const;
Empties all initialized members in the array, and the Buddiesinfo_size function returns 0 when the function is called.
inline void Clear_buddiesinfo ();
Returns a reference to the element contained in the specified subscript in the array.
Inline const::buddyinfo& buddiesinfo (int index) const;
Returns a pointer to the element contained in the specified subscript in the array, by which the value information of the element can be directly modified.
Inline:: buddyinfo* mutable_buddiesinfo (int index);
Add a new element like an array. The return value is the new element that can be initialized directly.
Inline:: buddyinfo* add_buddiesinfo ();
Gets the container represented by the Buddiesinfo field, which returns a container that is used only for traversal and reading and cannot be modified directly.
Inline const:: Google::p rotobuf::repeatedptrfield<:: Buddyinfo >&
Buddiesinfo () const;
Gets the container pointer represented by the Buddiesinfo field, which returns a container pointer that can be used for traversal and direct modification.
Inline:: Google::p rotobuf::repeatedptrfield<:: Buddyinfo >*
Mutable_buddiesinfo ();
Private
... ...
};

Here is the C + + test code and descriptive comment for the read-write Retrievebuddiesresp object.
Copy Code code as follows:

void Testrepeatedmessage ()
{
printf ("==================this is repeated message.================\n");
Retrievebuddiesresp Retrieveresp;
RETRIEVERESP.SET_BUDDIESCNT (2);
buddyinfo* buddyinfo = Retrieveresp.add_buddiesinfo ();
Buddyinfo->set_groupid (20);
userinfo* UserInfo = Buddyinfo->mutable_userinfo ();
Userinfo->set_acctid (200);
Userinfo->set_name ("user1");
Userinfo->set_status (OFFLINE);
Buddyinfo = Retrieveresp.add_buddiesinfo ();
Buddyinfo->set_groupid (21);
UserInfo = Buddyinfo->mutable_userinfo ();
Userinfo->set_acctid (201);
Userinfo->set_name ("User2");
Userinfo->set_status (ONLINE);
int length = Retrieveresp.bytesize ();
char* buf = new Char[length];
Retrieveresp.serializetoarray (buf,length);
Retrievebuddiesresp retrieveResp2;
Retrieveresp2.parsefromarray (buf,length);
printf ("Buddiescount =%d\n", retrieveresp2.buddiescnt ());
printf ("Repeated Size =%d\n", retrieveresp2.buddiesinfo_size ());
Only the test code that iterates through the array elements through the container iterator is provided here.
In fact, you can iterate through the buddiesinfo_size and Buddiesinfo functions.
repeatedptrfield<buddyinfo>* buddiesinfo = Retrieveresp2.mutable_buddiesinfo ();
Repeatedptrfield<buddyinfo>::iterator it = Buddiesinfo->begin ();
for (; it!= buddiesinfo->end (); ++it) {
printf ("Buddyinfo->groupid =%d\n", It->groupid ());
printf ("Userinfo->acctid =%i64d, Userinfo->name =%s, Userinfo->status =%d\n"
, It->userinfo (). Acctid (), It->userinfo (). Name (). C_STR (), It->userinfo (). status ());
}
delete [] buf;
}

Finally, the Protocol buffer still offers a number of other very useful features, especially for serialized destinations, such as file streams and network flows. At the same time, it also provides a complete set of official documentation and specification naming conventions, which in many cases can be learned directly by the function's name.

I intend to upload the sample code used in this blog as an attachment, but I do not find this feature, I hope to understand.

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.