Protocol Buffer

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]$ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值