http://www.jb51.net/article/33030.htm
http://www.cnblogs.com/royenhome/archive/2010/10/29/1864860.html
http://www.cnblogs.com/royenhome/archive/2010/10/30/1865153.html
一)这里先定义一个最简单的message,其中只是包含原始类型的字段
[lhm@localhost message]$ ll
总用量 4
-rw-rw-r--. 1 lhm lhm 124 8月 7 14:26 MyMessage.proto
[lhm@localhost message]$
[lhm@localhost message]$
[lhm@localhost message]$ cat MyMessage.proto
option optimize_for = LITE_RUNTIME;
message LogonReqMessage {
required int64 acctID = 1;
required string passwd = 2;
}
二)生成目标语言代码
[lhm@localhost ~]$ cat go
protoc -I=./message --cpp_out=./src message/MyMessage.proto
从上面的命令行参数中可以看出,待编译的文件为MyMessage.proto,他存放在当前目录的message子目录下。--cpp_out参数则指示编译工具我们需要生成目标语言是C++,输出目录是当前目录的src子目录。在本例中,生成的目标代码文件名是MyMessage.pb.h和MyMessage.pb.cc。
由于我们在MyMessage文件中定义选项optimize_for的值为LITE_RUNTIME,因此由该.proto文件生成的所有C++类的父类均为::google::protobuf::MessageLite,而非::google::protobuf::Message。在上一篇博客中已经给出了一些简要的说明,MessageLite类是Message的父类,在MessageLite中将缺少Protocol Buffer对反射的支持,而此类功能均在Message类中提供了具体的实现。对于我们的项目而言,整个系统相对比较封闭,不会和更多的外部程序进行交互,与此同时,我们的客户端部分又是运行在Android平台,有鉴于此,我们考虑使用LITE版本的Protocol Buffer。这样不仅可以得到更高编码效率,而且生成代码编译后所占用的资源也会更少,至于反射所能带来的灵活性和极易扩展性,对于该项目而言完全可以忽略。下面我们来看一下由message LogonReqMessage生成的C++类的部分声明,以及常用方法的说明性注释。
[lhm@localhost src]$ cat MyMessage.pb.cc
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: MyMessage.proto
#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
#include "MyMessage.pb.h"
#include <algorithm>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/once.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/wire_format_lite_inl.h>
// @@protoc_insertion_point(includes)
void protobuf_ShutdownFile_MyMessage_2eproto() {
delete LogonReqMessage::default_instance_;
}
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
void protobuf_AddDesc_MyMessage_2eproto_impl() {
GOOGLE_PROTOBUF_VERIFY_VERSION;
#else
void protobuf_AddDesc_MyMessage_2eproto() {
static bool already_here = false;
if (already_here) return;
already_here = true;
GOOGLE_PROTOBUF_VERIFY_VERSION;
#endif
LogonReqMessage::default_instance_ = new LogonReqMessage();
LogonReqMessage::default_instance_->InitAsDefaultInstance();
::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_MyMessage_2eproto);
}
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_MyMessage_2eproto_once_);
void protobuf_AddDesc_MyMessage_2eproto() {
::google::protobuf::::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_MyMessage_2eproto_once_,
&protobuf_AddDesc_MyMessage_2eproto_impl);
}
#else
// Force AddDescriptors() to be called at static initialization time.
struct StaticDescriptorInitializer_MyMessage_2eproto {
StaticDescriptorInitializer_MyMessage_2eproto() {
protobuf_AddDesc_MyMessage_2eproto();
}
} static_descriptor_initializer_MyMessage_2eproto_;
#endif
// ===================================================================
#ifndef _MSC_VER
const int LogonReqMessage::kAcctIDFieldNumber;
const int LogonReqMessage::kPasswdFieldNumber;
#endif // !_MSC_VER
LogonReqMessage::LogonReqMessage()
: ::google::protobuf::MessageLite() {
SharedCtor();
}
void LogonReqMessage::InitAsDefaultInstance() {
}
LogonReqMessage::LogonReqMessage(const LogonReqMessage& from)
: ::google::protobuf::MessageLite() {
SharedCtor();
MergeFrom(from);
}
void LogonReqMessage::SharedCtor() {
_cached_size_ = 0;
acctid_ = GOOGLE_LONGLONG(0);
passwd_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
LogonReqMessage::~LogonReqMessage() {
SharedDtor();
}
void LogonReqMessage::SharedDtor() {
if (passwd_ != &::google::protobuf::internal::kEmptyString) {
delete passwd_;
}
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
if (this != &default_instance()) {
#else
if (this != default_instance_) {
#endif
}
}
void LogonReqMessage::SetCachedSize(int size) const {
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
}
const LogonReqMessage& LogonReqMessage::default_instance() {
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
protobuf_AddDesc_MyMessage_2eproto();
#else
if (default_instance_ == NULL) protobuf_AddDesc_MyMessage_2eproto();
#endif
return *default_instance_;
}
LogonReqMessage* LogonReqMessage::default_instance_ = NULL;
LogonReqMessage* LogonReqMessage::New() const {
return new LogonReqMessage;
}
void LogonReqMessage::Clear() {
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
acctid_ = GOOGLE_LONGLONG(0);
if (has_passwd()) {
if (passwd_ != &::google::protobuf::internal::kEmptyString) {
passwd_->clear();
}
}
}
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
bool LogonReqMessage::MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input) {
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
::google::protobuf::uint32 tag;
while ((tag = input->ReadTag()) != 0) {
switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
// required int64 acctID = 1;
case 1: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
input, &acctid_)));
set_has_acctid();
} else {
goto handle_uninterpreted;
}
if (input->ExpectTag(18)) goto parse_passwd;
break;
}
// required string passwd = 2;
case 2: {
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) {
parse_passwd:
DO_(::google::protobuf::internal::WireFormatLite::ReadString(
input, this->mutable_passwd()));
} else {
goto handle_uninterpreted;
}
if (input->ExpectAtEnd()) return true;
break;
}
default: {
handle_uninterpreted:
if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
return true;
}
DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
break;
}
}
}
return true;
#undef DO_
}
void LogonReqMessage::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
// required int64 acctID = 1;
if (has_acctid()) {
::google::protobuf::internal::WireFormatLite::WriteInt64(1, this->acctid(), output);
}
// required string passwd = 2;
if (has_passwd()) {
::google::protobuf::internal::WireFormatLite::WriteString(
2, this->passwd(), output);
}
}
int LogonReqMessage::ByteSize() const {
int total_size = 0;
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
// required int64 acctID = 1;
if (has_acctid()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::Int64Size(
this->acctid());
}
// required string passwd = 2;
if (has_passwd()) {
total_size += 1 +
::google::protobuf::internal::WireFormatLite::StringSize(
this->passwd());
}
}
GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
_cached_size_ = total_size;
GOOGLE_SAFE_CONCURRENT_WRITES_END();
return total_size;
}
void LogonReqMessage::CheckTypeAndMergeFrom(
const ::google::protobuf::MessageLite& from) {
MergeFrom(*::google::protobuf::down_cast<const LogonReqMessage*>(&from));
}
void LogonReqMessage::MergeFrom(const LogonReqMessage& from) {
GOOGLE_CHECK_NE(&from, this);
if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
if (from.has_acctid()) {
set_acctid(from.acctid());
}
if (from.has_passwd()) {
set_passwd(from.passwd());
}
}
}
void LogonReqMessage::CopyFrom(const LogonReqMessage& from) {
if (&from == this) return;
Clear();
MergeFrom(from);
}
bool LogonReqMessage::IsInitialized() const {
if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false;
return true;
}
void LogonReqMessage::Swap(LogonReqMessage* other) {
if (other != this) {
std::swap(acctid_, other->acctid_);
std::swap(passwd_, other->passwd_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
std::swap(_cached_size_, other->_cached_size_);
}
}
::std::string LogonReqMessage::GetTypeName() const {
return "LogonReqMessage";
}
// @@protoc_insertion_point(namespace_scope)
// @@protoc_insertion_point(global_scope)
[lhm@localhost src]$
[lhm@localhost src]$ cat MyMessage.pb.h
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: MyMessage.proto
#ifndef PROTOBUF_MyMessage_2eproto__INCLUDED
#define PROTOBUF_MyMessage_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 2005000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
// @@protoc_insertion_point(includes)
// Internal implementation detail -- do not call these.
void protobuf_AddDesc_MyMessage_2eproto();
void protobuf_AssignDesc_MyMessage_2eproto();
void protobuf_ShutdownFile_MyMessage_2eproto();
class LogonReqMessage;
// ===================================================================
class LogonReqMessage : public ::google::protobuf::MessageLite {
public:
LogonReqMessage();
virtual ~LogonReqMessage();
LogonReqMessage(const LogonReqMessage& from);
inline LogonReqMessage& operator=(const LogonReqMessage& from) {
CopyFrom(from);
return *this;
}
static const LogonReqMessage& default_instance();
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
// Returns the internal default instance pointer. This function can
// return NULL thus should not be used by the user. This is intended
// for Protobuf internal code. Please use default_instance() declared
// above instead.
static inline const LogonReqMessage* internal_default_instance() {
return default_instance_;
}
#endif
void Swap(LogonReqMessage* other);
// implements Message ----------------------------------------------
LogonReqMessage* New() const;
void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
void CopyFrom(const LogonReqMessage& from);
void MergeFrom(const LogonReqMessage& from);
void Clear();
bool IsInitialized() const;
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
public:
::std::string GetTypeName() const;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// required int64 acctID = 1;
inline bool has_acctid() const;
inline void clear_acctid();
static const int kAcctIDFieldNumber = 1;
inline ::google::protobuf::int64 acctid() const;
inline void set_acctid(::google::protobuf::int64 value);
// required string passwd = 2;
inline bool has_passwd() const;
inline void clear_passwd();
static const int kPasswdFieldNumber = 2;
inline const ::std::string& passwd() const;
inline void set_passwd(const ::std::string& value);
inline void set_passwd(const char* value);
inline void set_passwd(const char* value, size_t size);
inline ::std::string* mutable_passwd();
inline ::std::string* release_passwd();
inline void set_allocated_passwd(::std::string* passwd);
// @@protoc_insertion_point(class_scope:LogonReqMessage)
private:
inline void set_has_acctid();
inline void clear_has_acctid();
inline void set_has_passwd();
inline void clear_has_passwd();
::google::protobuf::int64 acctid_;
::std::string* passwd_;
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32];
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
friend void protobuf_AddDesc_MyMessage_2eproto_impl();
#else
friend void protobuf_AddDesc_MyMessage_2eproto();
#endif
friend void protobuf_AssignDesc_MyMessage_2eproto();
friend void protobuf_ShutdownFile_MyMessage_2eproto();
void InitAsDefaultInstance();
static LogonReqMessage* default_instance_;
};
// ===================================================================
// ===================================================================
// LogonReqMessage
// required int64 acctID = 1;
inline bool LogonReqMessage::has_acctid() const {
return (_has_bits_[0] & 0x00000001u) != 0;
}
inline void LogonReqMessage::set_has_acctid() {
_has_bits_[0] |= 0x00000001u;
}
inline void LogonReqMessage::clear_has_acctid() {
_has_bits_[0] &= ~0x00000001u;
}
inline void LogonReqMessage::clear_acctid() {
acctid_ = GOOGLE_LONGLONG(0);
clear_has_acctid();
}
inline ::google::protobuf::int64 LogonReqMessage::acctid() const {
return acctid_;
}
inline void LogonReqMessage::set_acctid(::google::protobuf::int64 value) {
set_has_acctid();
acctid_ = value;
}
// required string passwd = 2;
inline bool LogonReqMessage::has_passwd() const {
return (_has_bits_[0] & 0x00000002u) != 0;
}
inline void LogonReqMessage::set_has_passwd() {
_has_bits_[0] |= 0x00000002u;
}
inline void LogonReqMessage::clear_has_passwd() {
_has_bits_[0] &= ~0x00000002u;
}
inline void LogonReqMessage::clear_passwd() {
if (passwd_ != &::google::protobuf::internal::kEmptyString) {
passwd_->clear();
}
clear_has_passwd();
}
inline const ::std::string& LogonReqMessage::passwd() const {
return *passwd_;
}
inline void LogonReqMessage::set_passwd(const ::std::string& value) {
set_has_passwd();
if (passwd_ == &::google::protobuf::internal::kEmptyString) {
passwd_ = new ::std::string;
}
passwd_->assign(value);
}
inline void LogonReqMessage::set_passwd(const char* value) {
set_has_passwd();
if (passwd_ == &::google::protobuf::internal::kEmptyString) {
passwd_ = new ::std::string;
}
passwd_->assign(value);
}
inline void LogonReqMessage::set_passwd(const char* value, size_t size) {
set_has_passwd();
if (passwd_ == &::google::protobuf::internal::kEmptyString) {
passwd_ = new ::std::string;
}
passwd_->assign(reinterpret_cast<const char*>(value), size);
}
inline ::std::string* LogonReqMessage::mutable_passwd() {
set_has_passwd();
if (passwd_ == &::google::protobuf::internal::kEmptyString) {
passwd_ = new ::std::string;
}
return passwd_;
}
inline ::std::string* LogonReqMessage::release_passwd() {
clear_has_passwd();
if (passwd_ == &::google::protobuf::internal::kEmptyString) {
return NULL;
} else {
::std::string* temp = passwd_;
passwd_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
return temp;
}
}
inline void LogonReqMessage::set_allocated_passwd(::std::string* passwd) {
if (passwd_ != &::google::protobuf::internal::kEmptyString) {
delete passwd_;
}
if (passwd) {
set_has_passwd();
passwd_ = passwd;
} else {
clear_has_passwd();
passwd_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
}
}
// @@protoc_insertion_point(namespace_scope)
// @@protoc_insertion_point(global_scope)
#endif // PROTOBUF_MyMessage_2eproto__INCLUDED
[lhm@localhost src]$
三)读写LogonReqMessage对象的C++测试代码和说明性注释。
[lhm@localhost src]$ cat test_msg.c
#include <iostream>
#include "MyMessage.pb.h"
#include <stdlib.h>
#include <stdio.h>
void testSimpleMessage(){
LogonReqMessage logonreq;
logonreq.set_acctid(2000000000);
logonreq.set_passwd("hello world");
int length = logonreq.ByteSize();
char *buff = new char[length];
logonreq.SerializeToArray( buff, length);
LogonReqMessage logonreq2;
logonreq2.ParseFromArray( buff, length );
printf("length=%d id=%64d, password=%s\n", length, logonreq2.acctid(), logonreq2.passwd().c_str() );
}
int main ( void ){
testSimpleMessage();
return 0;
}
[lhm@localhost src]$ cat go
g++ -lprotobuf test_msg.c MyMessage.pb.cc -o 1.exe
四)运行结果
[lhm@localhost src]$ cat go
g++ -lprotobuf test_msg.c MyMessage.pb.cc -o 1.exe
[lhm@localhost src]$ ./1.exe
length=19 id= 2000000000, password=hello world
五)扩展
[lhm@localhost message]$ cat MyRepeat.proto
enum UserStatus {
OFFLINE = 0;
ONLINE = 1;
}
message UserInfo {
required int64 acctID = 1;
required string name = 2;
required UserStatus status = 3;
}
message BuddyInfo {
required UserInfo userInfo = 1;
required int32 groupID = 2;
}
message RetrieveBuddiesResp {
required int32 buddiesCnt = 1;
repeated BuddyInfo buddiesInfo = 2;
}
测试代码
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include "MyRepeat.pb.h"
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());
//这里仅提供了通过容器迭代器的方式遍历数组元素的测试代码。
事实上,通过buddiesinfo_size和buddiesinfo函数亦可循环遍历。
::google::protobuf::RepeatedPtrField<BuddyInfo>* buddiesInfo = retrieveResp2.mutable_buddiesinfo();
::google::protobuf::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());
}
printf("\n\n");
int size= retrieveResp2.buddiesinfo_size();
for(int i=0; i<size; i++){
BuddyInfo buddiesInfo = retrieveResp2.buddiesinfo(i);
printf("BuddyInfo->groupID = %d\n", buddiesInfo.groupid());
printf("UserInfo->acctID = %I64d, UserInfo->name = %s, UserInfo->status = %d\n"
,buddiesInfo.userinfo().acctid(),buddiesInfo.userinfo().name().c_str(), buddiesInfo.userinfo().status());
}
delete [] buf;
}
int main(){
testRepeatedMessage();
return 0;
}
结果:
[lhm@localhost src]$ ./repeat.exe
==================This is repeated message.================
BuddiesCount = 2
Repeated Size = 2
BuddyInfo->groupID = 20
UserInfo->acctID = 200, UserInfo->name = user1, UserInfo->status = 0
BuddyInfo->groupID = 21
UserInfo->acctID = 201, UserInfo->name = user2, UserInfo->status = 1
BuddyInfo->groupID = 20
UserInfo->acctID = 200, UserInfo->name = user1, UserInfo->status = 0
BuddyInfo->groupID = 21
UserInfo->acctID = 201, UserInfo->name = user2, UserInfo->status = 1
[lhm@localhost src]$