序列化和反序列化及Protobuf 基本使用

序列化和反序列化

序列化和反序列化在日常工做中會大量使用,然而並不必定很是清楚它的概念。序列化和反序列化的選型倒是系統設計或重構一個重要的環節,在分佈式、大數據量系統設計裏面更爲顯著。機器間的通訊須要約定一個協議,序列化和反序列化是這個通訊協議的一部分。
序列化:將對象或數據結構轉爲字節序列的過程。
反序列化:將序列化後生成的字節序列轉爲對象或數據結構的過程。分佈式

經常使用序列化和反序列化組件

比較常見的序列化和反序列化組方式有XML、JSON和Protobuf等。XML標準化較早,基於XML的SOAP是一種應用普遍的結構化數據傳遞協議。JSON源於js,較之XML它更小、解析更快,並且一樣具有可讀性好的優勢。而源於谷歌的protobuf如今在大型分佈式系統普遍使用。大數據

Protobuf

Protobuf是谷歌推出的一款平臺無關,語言無關,可擴展的序列化和反序列化技術。ui

字段規則

要使用Protobuf,首先須要定義.proto文件
以下proto2中:編碼

message msg
{
    required int32 a=1;
    optional string b=2;
    repeated string c=3;
}

其中:spa

  • message是消息定義的關鍵字。
  • required 表示這個字段必須的,必須在序列化的時候被賦值。
  • optional 表明這個字段是可選的,能夠爲0個或1個但不能大於1個。
  • repeated 則表明此字段能夠被重複任意屢次包括0次。相似C++ STL中的vector。
  • int32和string是字段的類型。後面是咱們定義的字段名。
  • 最後的1,2,3則是表明每一個字段的一個惟一的編號標籤,在同一個消息裏不能夠重複。這些編號標籤用與在消息二進制格式中標識你的字段,而且消息一旦定義就不能更改。須要說明的是標籤在1到15範圍的採用一個字節進行編碼。因此一般將標籤1到15用於頻繁發生的消息字段。編號標籤大小的範圍是1到\(2^{29}-1\)。此外不能使用protobuf系統預留的編號標籤(19000 -19999)。

而在proto3中,字段規則中去除了required和optional,增長singular。可是proto3仍兼容proto2設計

message msg
{
    int32 a=1;
    singular string b=2;
    repeated string c=3;
}

其中,code

  • singular:一個格式良好的消息應該有0個或者1個這種字段(可是不能超過1個)。
  • repeated
  • 在proto3中,repeated的標量域默認狀況下使用packed。

一個較完整的.proto文件對象

syntax = "proto3";
message Article {
  int32 article_id = 1;
  singular string article_excerpt = 2;
  repeated string article_picture = 3;
  singular int32  article_pagecount = 4 [default = 0];
  enum ArticleType {
    NOVEL = 0;
    PROSE = 1;
    PAPER = 2;
    POETRY = 3;
  }
  singular ArticleType article_type = 5 [default = NOVEL];
  message Author {
    string name = 1; 
    singular string phone = 2;
  }
  singular Author author = 6;
  repeated int32 article_numberofwords = 7 [packed=true];
  reserved  9, 10, 12 to 15;
  extensions 100 to 1000;
}

extend Article {
  singular int32 followers_count = 101;
  singular int32 likes_count= 102;
}

message Other {
  singular string other_info = 1;
  oneof test_oneof {
    string code1 = 2;
    string code2 = 3;
  }
}
  • 上面proto文件,咱們定義了enum枚舉類型,嵌套的消息。甚至對原有的消息進行了擴展,也能夠對字段設置默認值。添加註釋等,相似C++註釋。
  • 此外reserved關鍵字主要用於保留相關編號標籤,主要是防止在更新proto文件刪除了某些字段,而將來的使用者定義新的字段時從新使用了該編號標籤。這會引發一些問題在獲取老版本的消息時,譬如數據衝突,隱藏的一些bug等。因此必定要用reserved標記這些編號標籤以保證不會被使用。
  • 當咱們須要對消息進行擴展的時候,咱們能夠用extensions關鍵字來定義一些編號標籤供第三方擴展。這樣的好處是不須要修改原來的消息格式。就像上面proto文件,咱們用extend關鍵字來擴展。只要擴展的字段編號標籤在extensions定義的範圍裏。
  • 對於基本數值類型,因爲歷史緣由,不能被protobuf更有效的encode。因此在新的代碼中使用packed=true能夠更加有效率的encode。注意packed只能用於repeated 數值類型的字段。不能用於string類型的字段。
  • 在消息Other中咱們看到定義了一個oneof關鍵字。這個關鍵字做用比較有意思。當你設置了oneof裏某個成員值時,它會自動清除掉oneof裏的其餘成員,也就是說同一時刻oneof裏只有一個成員有效。這經常使用於你有許多optional字段時但同一時刻只能使用其中一個,就能夠用oneof來增強這種效果。但須要注意的是oneof裏的字段不能用singular,repeated關鍵字。

導入定義

咱們總不能都定義在一個文件中。當一個proto文件須要另外一個proto文件的時候,咱們能夠經過import導入。protobuf也提供了包的定義,只要在文件開頭定義package關鍵字便可。string

import "test.proto"
package foo.bar;

編譯問題

針對不一樣語言,依據.proto文件編譯成咱們須要的語言文件。如C++下

protoc -I=SRC_DIR --cpp_out=DST_DIR SRC_DIR/ex.proto

先簡單記錄這些。

相關文章
相關標籤/搜索