Protocol Buffer入門(mén)簡(jiǎn)介

一、Protocol buffers簡(jiǎn)述

特點(diǎn)

Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data.

  • 語(yǔ)言中立,平臺(tái)中立
  • 序列化結(jié)構(gòu)化數(shù)據(jù)

protocol核心學(xué)習(xí)點(diǎn)

優(yōu)勢(shì)

  • simpler(簡(jiǎn)單)
  • smaller(文件小)
  • faster(序列化與反序列化速度快)
  • 支持多種語(yǔ)言,相對(duì)于xml更易于程序處理

主要是由于采用protocol方式生成的binary format文件相比于xml格式的更小,序列化,反序列化,網(wǎng)絡(luò)傳輸過(guò)程中有更大優(yōu)勢(shì)。

歷史演變主要解決的問(wèn)題

  • 協(xié)議不同版本的字段變換時(shí)帶來(lái)的兼容性問(wèn)題
  • 協(xié)議能夠帶來(lái)了更好的自描述,能夠被不同語(yǔ)言處理

演變歷程

  • 自動(dòng)產(chǎn)生序列化與反序列化代碼-》如何使用?
  • 利用protocol buffer自描述能力,用于大數(shù)據(jù)存儲(chǔ)-》如何存儲(chǔ),效率問(wèn)題如何?
  • 能夠使用編譯器能夠自動(dòng)生成服務(wù)端stub程序-》如何生成?

二、Proto3 buffer語(yǔ)法格式

暫時(shí)跳過(guò)proto2的語(yǔ)法格式

2.1 Defining A Message Type

如何在proto文件中定義一個(gè)消息類型?

syntax = "proto3"

message request {
    string name = 1;
    string age=2;
    int32 page_numer = 3;
    int32 result_per_page = 4;
}

proto messge主要有field types, field name以及field number構(gòu)成。

其中field number 【1-15】區(qū)間占用One Byte,【16-2047】占用兩個(gè)bytes,所以在message中fields個(gè)數(shù)不多的情況,盡量使用1-15之內(nèi)的數(shù)值。

field number允許的值范圍為【1-2的29次方-1(536870911)】,其中【19000-19999】為保留數(shù)值。

Adding Comments

proto use c/c++ style comments, //for line comments, /.../for block comment

Reserved Fields

message ReservedTest{
    reserved 2, 6, 10 to max;
    reserved "name", "age";
}

Note:不能在同一行混用field name與number,必須分開(kāi)保留。

2.2 編譯proto文件

對(duì)于一個(gè)初學(xué)者來(lái)說(shuō),剛開(kāi)始肯定會(huì)拿到一個(gè)proto文件,拿到此文件后如何下手?大致步驟如下:

  1. 安裝編譯環(huán)境,protocol buffer compiler能夠根據(jù)不同的客戶端語(yǔ)言,生成對(duì)應(yīng)的代碼,規(guī)則如下

    For C++, the compiler generates a .h and .cc file from each .proto, with a class for each message type described in your file.

    For Java, the compiler generates a .java file with a class for each message type, as well as a special Builder classes for creating message class instances.

    Python is a little different – the Python compiler generates a module with a static descriptor of each message type in your .proto, which is then used with a metaclass to create the necessary Python data access class at runtime.

    For Go, the compiler generates a .pb.go file with a type for each message type in your file.

    For Ruby, the compiler generates a .rb file with a Ruby module containing your message types.

    For Objective-C, the compiler generates a pbobjc.h and pbobjc.m file from each .proto, with a class for each message type described in your file.

    For C#, the compiler generates a .cs file from each .proto, with a class for each message type described in your file.

    For Dart, the compiler generates a .pb.dart file with a class for each message type in your file

  2. 運(yùn)行編譯指令

2.3 Scalar Value Types

描述protocol文件的field types如何與其他不同語(yǔ)言的數(shù)據(jù)類型進(jìn)行一一映射。

具體映射關(guān)系參考protocol數(shù)據(jù)類型映射表

protocol中定義的數(shù)據(jù)類型:

double,float,int32,int64,uint32, uint64, sint32, sint64, fixed32, fixed64, sfixed32, sfixed64, bool, string, bytes

對(duì)于不同數(shù)據(jù)類型,不同操作數(shù)據(jù)類型,在數(shù)據(jù)序列化與反序列化的時(shí)候,會(huì)對(duì)不同數(shù)據(jù)類型進(jìn)行一定的優(yōu)化。

2.4 Default values

在message被反序列化的時(shí)候,如果缺少特定field的描述,反序列化時(shí)就會(huì)設(shè)置對(duì)應(yīng)的默認(rèn)值,規(guī)則如下:

  • For strings, the default value is the empty string.—空字符串
  • For bytes, the default value is empty bytes.—空字節(jié)
  • For bools, the default value is false.-錯(cuò)
  • For numeric types, the default value is zero.-0
  • For enums, the default value is the first defined enum value, which must be 0.-聯(lián)合第一個(gè)值必須為0
  • For message fields, the field is not set. Its exact value is language-dependent. See the generated code guide for details.

2.5 Enumerations

聯(lián)合是protocol中相對(duì)復(fù)雜的type,例如

message request {
    string name = 1;
    int age = 2;
    enum Sex {
        MALE = 0;
        FEMALE = 1;
        OTHER = 2
    }
    Sex gender = 3;
}

在protocol中對(duì)enum的第一個(gè)元素作了特別的規(guī)定,必須為值為0,主要是為了解決enum的默認(rèn)值問(wèn)題以及兼容proto2協(xié)議。

聯(lián)合字段別名

示例:

message request {
    string name = 1;
    int age = 2;
    enum Sex {
        option allow_alias = true;
        MALE = 0;
        FEMALE = 1;
        MAN = 1;
        OTHER = 2
    }
    Sex gender = 3;
}

允許聯(lián)合字段別名在Java或者C語(yǔ)言中比較少見(jiàn),protocol默認(rèn)也不允許開(kāi)啟聯(lián)合別名,如果要開(kāi)啟必須通過(guò)手動(dòng)打開(kāi)配置選項(xiàng)

2.6 Using Other Message Types

protocol文件之間如何相互引用已經(jīng)定義好的Message?如何通過(guò)Message嵌套引用形成消息結(jié)構(gòu)層次?

示例:

message Response {
    int http_code = 1;
    string ret_msg = 2;
    repeated Device data = 3;
}

message Result {
    string device_uuid = 1;
    string device_name = 2;
    float longitude = 3;
    float latitude = 4;
}

一般來(lái)說(shuō),在實(shí)際的代碼開(kāi)發(fā)過(guò)程中,盡量將Message顆粒度進(jìn)行拆分,便于在項(xiàng)目中相互調(diào)用。

importing definitions

protocol也支持導(dǎo)入其他proto文件,通過(guò)proto文件導(dǎo)入方式,能夠通過(guò)合并導(dǎo)入proto文件形成新的proto文件,可以對(duì)不通版本,用戶暴露不一樣的proto文件。

2.7 Unknown Fields

對(duì)于解析端,如果解析的數(shù)據(jù)流中包含一些未知字段,通常來(lái)說(shuō)解析時(shí)候把未知字段給忽略了,但是在protocol3.5及以后的版本中,未知字段在解析時(shí)候會(huì)被保留而不是丟棄。

2.8 Any

protocol中提供了一種特殊的消息類型Any。 Any的意思為:字段可以為任何類型,在序列化時(shí)候就將此字段序列化為bytes。

示例:

import "google/protobuf/any.proto";

message ErrorStatus {
    string message = 1;
    repeated google.protobuf.Any details = 2;
}

在使用Any消息類型的時(shí)候,必須引入google的any這個(gè)proto文件。對(duì)于Any的使用場(chǎng)景需要收集總結(jié)?

2.9 Oneof

Oneof用于標(biāo)記消息中某些字段同時(shí)最多只有一個(gè)能夠同時(shí)存在,經(jīng)常用于標(biāo)記互斥的字段。

示例:

message Person {
    oneof contact {
        string mobile = 4;
        string email = 9;
    }
}

Oneof Features

注意在實(shí)際消息對(duì)象賦值的過(guò)程中,oneof特性帶來(lái)值覆蓋問(wèn)題,最終值是最后一個(gè)oneof字段,oneof字段不允許使用repeated。

oneof使用案例

2.10 Maps

Maps也是最常見(jiàn)的數(shù)據(jù)類型。

示例

map<string, Person> class = 2;

protocol對(duì)map做了以下限定

  1. key必須為inegral以及string,value可以為除了map后的任何類型
  2. map不能用repeated來(lái)進(jìn)行修飾
  3. 不允許有重復(fù)的key
  4. 對(duì)于只有key沒(méi)有value情況,不同語(yǔ)言處理方式不一樣

2.11 Packages

protocol為了防止定義的消息類型沖突,也引入了package概念,類似于java,c++等語(yǔ)言,protocol的包在轉(zhuǎn)換為不同語(yǔ)言實(shí)現(xiàn)時(shí),會(huì)有相關(guān)轉(zhuǎn)換關(guān)系。

定義一個(gè)包的消息:

package com.dwx;

message Person {
}

引入一個(gè)包對(duì)象

message Class {
    com.dwx.Person stu = 1;
}

在proto文件轉(zhuǎn)換為java文件時(shí),默認(rèn)用定義的package名來(lái)作為java的包名,如果想改變?cè)撘?guī)律,可以使用配置項(xiàng)

option java_package = "com.xx.xx"

2.12 Defining Services

proto文件中除了定義消息類型,另一個(gè)重要任務(wù)就是服務(wù)接口。編譯器會(huì)根據(jù)選擇的語(yǔ)言生成相應(yīng)的接口代碼以及存根代碼。

常見(jiàn)的service示例

service SearchPerson {
    rpc Search(Person) returns(Class);
}

不同的編譯插件可以快速生成對(duì)應(yīng)的interface以及stub代碼,需要深入研究maven或者gradle方式下如何集成相關(guān)插件,運(yùn)行指令等

2.13 Options

proto buffer提供可選項(xiàng)參數(shù),用于改變編譯的一些默認(rèn)行為,目前主要有針對(duì)java或者移動(dòng)端的一些優(yōu)化配置,匯總?cè)缦?

  1. java_package: 改變java的默認(rèn)package名

    option java_package = "xx.xx.xx"

  2. java_ multiple_files:是否將messages,enums以及services作為內(nèi)部類

    option java_ multiple_files = true

  3. java_outer _classname:指定outerclass名字,默認(rèn)為proto文件名

    option java_outer _classname = "PersonStu"

  4. optimize_ for:可以被設(shè)置為SPEED,CODE_SIZE,LITE_RUNTIME。通過(guò)設(shè)置優(yōu)化屬性,代碼產(chǎn)生器會(huì)針對(duì)不同的語(yǔ)言進(jìn)行各種優(yōu)化。

Custom Options:可以自己定義優(yōu)化特性。

3 如何生成class

3.1 環(huán)境準(zhǔn)備

  1. 安裝編譯環(huán)境,windows平臺(tái)下可以選擇windows protoc 3.6.1安裝文件

  2. 配置系統(tǒng)環(huán)境變量,在path中添加bin路徑,例如 D:\IDE\protoc-3.6.0-win32\bin

  3. 在cmd命令行下,輸入protoc --version,回顯libprotoc XXX, XXX為安裝的版本號(hào)

3.2 編寫(xiě).proto文件

syntax = "proto3"

message PersonRequest{

    string name = 1; //姓名
    uint32 age = 2; //年齡
    string birth_day = 3; //出生日期
    string mobile = 4; //手機(jī)號(hào)
    enum Sex {
        Female = 0;
        Male = 1;
        Other = 2;
    }
    Sex gender = 5; //define sex
}

3.3 命令行編譯

指令格式如下:

protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto 

其中各個(gè)參數(shù)的含義如下:

  • --proto_path:簡(jiǎn)寫(xiě)-I, 為import文件的路徑,缺省為當(dāng)前文件路徑。
  • --**_output,主要為編譯器根據(jù)不同語(yǔ)言產(chǎn)生的代碼文件,如果DST——DIR是.zip或者.jar,編譯器會(huì)根據(jù)要求生成相應(yīng)的文件
  • 提供一個(gè)或者多個(gè)文件作為輸入文件,文件默認(rèn)也是參考當(dāng)前的路徑。

3.4 案例演示

  1. 編寫(xiě)Person.proto文件
  2. 運(yùn)行protoc --java_out ./rpc/out/person.jar --go_out .\rpc\out\go\ .\rpc\Person.proto,報(bào)"--go_out:protoc-gen-go:系統(tǒng)找不到指定的文件",主要是編譯器中不包含golang的代碼生成器,刪除掉go的out文件即可。
  3. 重新運(yùn)行protoc --java_ out ./rpc/out/person.jar .\rpc\Person.proto,即可生成對(duì)應(yīng)的jar文件,主要out_dst文件夾必須為已存在,未存在的目錄代碼生成器不會(huì)自動(dòng)創(chuàng)建。
  4. 可以通過(guò)修改配置項(xiàng)來(lái)調(diào)整生成的jar的內(nèi)容

4 code style

代碼約定:

  1. Message名:用駝峰,第一個(gè)字母為大寫(xiě),如PersonRequest
  2. 字段名字用小寫(xiě),名字用下劃線之間分割,例如:birth_date
  3. 聯(lián)合全部用大寫(xiě)
  4. service名字用大寫(xiě),service中的方法名也用大寫(xiě)首字母+駝峰命名
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,610評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,939評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,668評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,004評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,173評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,426評(píng)論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,656評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,833評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,247評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,580評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,371評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,621評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容

  • 翻譯查閱外網(wǎng)資料過(guò)程中遇到的比較優(yōu)秀的文章和資料,一是作為技術(shù)參考以便日后查閱,二是訓(xùn)練英文能力。此文翻譯自 Pr...
    401閱讀 68,330評(píng)論 1 39
  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi閱讀 7,415評(píng)論 0 10
  • 遇見(jiàn),何需時(shí)間地點(diǎn); 懂你,何需千言萬(wàn)語(yǔ)。 如果,懂,是一種簡(jiǎn)簡(jiǎn)單單的感動(dòng),那么相互感動(dòng)可好 如果,懂,是一種難言...
    譚先生啦閱讀 268評(píng)論 0 1
  • 2018年7月21日 星期六 晴 前幾天,一個(gè)微信上的好友問(wèn)我是不是少數(shù)民族,我的微信昵稱怎么叫香秋卓瑪,是不是...
    彩虹老師閱讀 6,526評(píng)論 2 6
  • 什么是OAuth? OAuth(Open Authorization,開(kāi)放授權(quán))是為用戶資源的授權(quán)定義了一個(gè)安全、...
    PHPer_閱讀 3,734評(píng)論 1 6