google protocol buffer的原理和使用(一)

 1、簡單的介紹

     Protocol buffers是一個用來序列化結構化數據的技術,支持多種語言諸如C++、Java以及Python語言。可以使用該技術來持久化數據或者序列化成網絡傳輸的數據。相比較一些其它的XML技術而言。該技術的一個明顯特色就是更加節省空間(以二進制流存儲)、速度更快以及更加靈活。

     一般,編寫一個protocol buffers應用需要經歷例如如下三步:數組


     一、定義消息格式文件。最好以proto做爲後綴名

     二、使用Google提供的protocol buffers編譯器來生成代碼文件,通常爲.h和.cc文件,主要是對消息格式以特定的語言方式描寫敘述

     三、使用protocol buffers庫提供的API來編寫應用程序  

     2、定義Proto文件 

     proto文件即消息協議原型定義文件,在該文件裏咱們可以經過使用描寫敘述性語言,來良好的定義咱們程序中需要用到數據格式。

首先咱們可以經過Google在線文檔上提供的一個電話簿的樣例來了解下。只是略微加了點修改。     

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;
  
  required bytes  unsure = 5;      //Add byte array here    
}

message AddressBook {
  repeated Person person = 1;
}

     誠如你看到的同樣,消息格式定義很是easy。對於每個字段而言都有一個修飾符(required/repeated/optional)、字段類型(bool/string/bytes/int32等)和字段標籤(Tag)組成。

     三個修飾符從詞義上可以很是清楚的弄明確。

    1)對於required的字段而言,初值是必須要提供的,不然字段的即是未初始化的。網絡

在Debug模式的buffer庫下編譯的話,序列化話的時候可能會失敗,而且在反序列化的時候對於該字段的解析會老是失敗的。因此,對於修飾符爲required的字段,請在序列化的時候務必給予初始化。函數




    2)對於optional的字段而言,假設未進行初始化。那麼一個默認值將賦予該字段。固然也可以指定默認值。如上述proto定義中的PhoneType字段類型。

    3)對於repeated的字段而言,該字段可以反覆多個,google提供的這個addressbook樣例便有個很是好的該修飾符的應用場景,即每個人可能有多個電話號碼。在高級語言裏面,咱們可以經過數組來實現,而在proto定義文件裏可以使用repeated來修飾,從而達到一樣目的。固然。出現0次也是包括在內的。ui

     

    當中字段標籤標示了字段在二進制流中存放的位置,這個是必須的,而且序列化與反序列化的時候一樣的字段的Tag值必須相應,不然反序列化會出現意想不到的問題。

google

     3、編譯proto文件。生成特定語言數據的數據定義代碼  指針


     在定義好了proto文件。就可以將該文件做爲protocol buffers編譯器的輸入文件。編譯產生特定語言的數據定義代碼文件了。本文主要是針對C++語言,因此使用編譯器後生成的是.h與.cc的代碼文件。對於C++、Java還有Python都有各自的編譯器。下載地址:http://code.google.com/p/protobuf/downloads/list  

     當你下載完了相應的編譯器二進制文件後。就可以使用下列命令來完畢編譯過程:

     protoc.exe -proto_path=SRC --cpp_out=DST SRC/addressbook.proto 

     當中--proto_path指出proto文件所在的文件夾,--cpp_out則是生成的代碼文件要放的文件夾,最後的一個參數指出proto文件的路徑。如上述命令中可以看出,將SRC文件夾下的addressbook.proto編譯後放在DST文件夾下。應該會生成addressbook.pb.h和addressbook.pb.cc文件(/Files/royenhome/addressbook.rar)。



     經過查看頭文件,可以發現針對每個字段都會大體生成例如如下幾種函數,以number爲例:

  // required string number = 1;
  inline bool has_number() const;
  inline void clear_number();
  inline const ::std::string& number() const;
  inline void set_number(const ::std::string& value);
  inline void set_number(const char* value);
  inline ::std::string* mutable_number();

      可以看出。對於每個字段會生成一個has函數(has_number)、clear清除函數(clear_number)、set函數(set_number)、get函數(number和mutable_number)。這兒解釋下get函數中的兩個函數的差異,對於原型爲const std::string &number() const的get函數而言,返回的是常量字段,不能對其值進行改動。但是在有一些狀況下,對字段進行改動是必要的。因此提供了一個mutable版的get函數,經過獲取字段變量的指針,從而達到改變其值的目的。

      而對於字段修飾符爲repeated的字段生成的函數。則略微有一些不一樣,如phone字段,則編譯器會爲其產生例如如下的代碼: 

  // repeated .Person.PhoneNumber phone = 4;
  inline int phone_size() const;
  inline void clear_phone();
  inline const ::google::protobuf::RepeatedPtrField< ::Person_PhoneNumber >& phone() const;
  inline ::google::protobuf::RepeatedPtrField< ::Person_PhoneNumber >* mutable_phone();
  inline const ::Person_PhoneNumber& phone(int index) const;
  inline ::Person_PhoneNumber* mutable_phone(int index);
  inline ::Person_PhoneNumber* add_phone();


      可以看出,set函數變成了add函數,這個事實上很是好理解。code

上面也說過。repeated修飾的字段在高級語言中的實現多是個數組或動態數組,因此固然經過加入的方式來加入新的字段值。而起get函數也變化很是大。這個也不用多說了。

文檔

     好了。本文主要是對了解protocol buffer做了些簡單的介紹,固然更具體的仍是看官方文檔。get

相關文章
相關標籤/搜索