protobuf入門

來源:互聯網
上載者:User

protobuf全稱Protocol Buffers,是google推出的一種高效,快捷的資料交換格式,和XML,Thrift一樣,都是一種資料交換協議(當然thrift還提供rpc的功能)。protobuf相對與xml結構化的文本資料格式,它是一種二進位的資料格式,具有更高的傳輸,打包和解包效率,這也是為什麼protobuf很受歡迎的原因。

protobuf通過自己的編譯器,對協議檔案進行編譯,產生對應語言的代碼,方便的進行資料的打包和解包。目前,google 提供了三種語言的實現:java、c++ 和python,每一種實現都包含了相應語言的編譯器以及庫檔案。

下面介紹protobuf的文法,protobuf的IDL都是儲存為*.proto的檔案中,proto檔案中資料類型可以分為兩大類:複合資料型別和標準資料類型。複合資料型別包括:枚舉message類型標準資料類型包含:整型,浮點,字串等,後面會詳細介紹。 message

最常用的資料格式就是message,例如一個訂單資料可以用message表示如下:

message Order{    required uint64 uid = 1;    required float cost = 2;    optional string tag = 3;}
它經過protobuf編譯成c++代碼,會產生對應的XXX.pb.h和XXX.pb.cc。message會對應產生一個class,裡面存放對應的data members,處理這些資料的函數,以及對應的打包和解包函數。
class Order : public ::google::protobuf::Message { public:  ...  // accessors -------------------------------------------------------  ...  ::google::protobuf::uint64 uid_;  ::std::string* tag_;  float cost_;};
message資料格式中需要知道的:

1.每個欄位末尾賦值的tag:該tag是用來標記該欄位在序列化後的位元據中所在的field,每個欄位的tag在message內部都是獨一無二的。也不能進行改變,否則資料就不能正確的解包。

2.資料類型前面的修飾詞:

required: 必須賦值,不可為空,否則該條message會被認為是“uninitialized”。build一個“uninitialized” message會拋出一個RuntimeException異常,解析一條“uninitialized” message會拋出一條IOException異常。除此之外,“required”欄位跟“optional”欄位並無差別。 optional:欄位可以賦值,也可以不賦值。假如沒有賦值的話,會被賦上預設值。 repeated: 該欄位可以重複任意次數,包括0次。重複資料的順序將會儲存在protocol buffer中,將這個欄位想象成一個可以自動化佈建size的數組就可以了。 枚舉

枚舉和c++,java中的枚舉類型是一個含義:

enum Corpus {UNIVERSAL = 0; WEB = 1;IMAGES = 2;LOCAL = 3; NEWS = 4; PRODUCTS = 5;VIDEO = 6;}

執行 protoc --cpp_out=.  enum_test.proto,會產生以下c++代碼

enum Corpus {  UNIVERSAL = 0,  WEB = 1,  IMAGES = 2,  LOCAL = 3,  NEWS = 4,  PRODUCTS = 5,  VIDEO = 6};

基礎資料型別 (Elementary Data Type)

protobuf支援的基礎資料型別 (Elementary Data Type)如下圖:


message詳解:

message資料格式在c++中被protobuf自動編譯包含一下內容:

//xxx.protomessage Order{    required uint64 uid = 1;    required float cost = 2;    optional string tag = 3;}//xxx.pb.h<pre name="code" class="cpp">class Order : public ::google::protobuf::Message { public:  ...  // accessors -------------------------------------------------------  // required uint64 uid = 1;  inline bool has_uid() const;  inline void clear_uid();  static const int kUidFieldNumber = 1;  inline ::google::protobuf::uint64 uid() const;  inline void set_uid(::google::protobuf::uint64 value);  // required float cost = 2;  inline bool has_cost() const;  inline void clear_cost();  static const int kCostFieldNumber = 2;  inline float cost() const;  inline void set_cost(float value);  // optional string tag = 3;  inline bool has_tag() const;  inline void clear_tag();  static const int kTagFieldNumber = 3;  inline const ::std::string& tag() const;  inline void set_tag(const ::std::string& value);  inline void set_tag(const char* value);  inline void set_tag(const char* value, size_t size);  inline ::std::string* mutable_tag();  inline ::std::string* release_tag();  inline void set_allocated_tag(::std::string* tag);  // @@protoc_insertion_point(class_scope:Order) private:  inline void set_has_uid();  inline void clear_has_uid();  inline void set_has_cost();  inline void clear_has_cost();  inline void set_has_tag();  inline void clear_has_tag();  ::google::protobuf::uint32 _has_bits_[1];  ::google::protobuf::uint64 uid_;  ::std::string* tag_;  float cost_;};
 對於每一個message的data member,protobuf會自動產生相關的處理函數,對於每一個欄位主要的處理函數有:has_uid(), clear_uid(), uid(), set_uid(),它們分別用於判斷該欄位是否被設定,清除該欄位設定記錄,獲得該欄位,設定該欄位。對於樣本中的uid欄位,對應函數的實現如下: 

//xxx.pb.h// required uint64 uid = 1;inline bool Order::has_uid() const {  return (_has_bits_[0] & 0x00000001u) != 0;}inline void Order::set_has_uid() {  _has_bits_[0] |= 0x00000001u;}inline void Order::clear_has_uid() {  _has_bits_[0] &= ~0x00000001u;}inline void Order::clear_uid() {  uid_ = GOOGLE_ULONGLONG(0);  clear_has_uid();}inline ::google::protobuf::uint64 Order::uid() const {  // @@protoc_insertion_point(field_get:Order.uid)  return uid_;}inline void Order::set_uid(::google::protobuf::uint64 value) {  set_has_uid();  uid_ = value;  // @@protoc_insertion_point(field_set:Order.uid)}
由實現代碼可知,代碼是通過_has_bits_來標記欄位是否已經被設定,_has_bits_的定義如下:
::google::protobuf::uint32 _has_bits_[1];

 通過_has_bits_的位來表達各個欄位是否被設定。分別通過0x01, 0x02, 0x04...來分別標記第1,2,3,,,各個field是否已經被設定。 

對於protobuf將協議資料序列化為位元據的介面有如下:

// Serialization ---------------------------------------------------  // Methods for serializing in protocol buffer format.  Most of these  // are just simple wrappers around ByteSize() and SerializeWithCachedSizes().  // Write a protocol buffer of this message to the given output.  Returns  // false on a write error.  If the message is missing required fields,  // this may GOOGLE_CHECK-fail.  bool SerializeToCodedStream(io::CodedOutputStream* output) const;  // Like SerializeToCodedStream(), but allows missing required fields.  bool SerializePartialToCodedStream(io::CodedOutputStream* output) const;  // Write the message to the given zero-copy output stream.  All required  // fields must be set.  bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const;  bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const;  // Serialize the message and store it in the given string.  All required  // fields must be set.  bool SerializeToString(string* output) const;  bool SerializePartialToString(string* output) const;  // Serialize the message and store it in the given byte array.  All required  // fields must be set.  bool SerializeToArray(void* data, int size) const;  bool SerializePartialToArray(void* data, int size) const;  string SerializeAsString() const;  string SerializePartialAsString() const;  // Like SerializeToString(), but appends to the data to the string's existing  // contents.  All required fields must be set.  bool AppendToString(string* output) const;  bool AppendPartialToString(string* output) const;  // Serialize the message and write it to the given file descriptor.  All  // required fields must be set.  bool SerializeToFileDescriptor(int file_descriptor) const;  bool SerializePartialToFileDescriptor(int file_descriptor) const;  // Serialize the message and write it to the given C++ ostream.  All  // required fields must be set.  bool SerializeToOstream(ostream* output) const;  bool SerializePartialToOstream(ostream* output) const;


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.