摘要:優點在谷歌內部長期使用產品成熟度高跨語言支持多種語言包括和編碼后的消息更小更加有利于存儲和傳輸編解碼的性能非常高支持不同協議版本的前向兼容支持定義可選和必選字段的入門是一個靈活高效結構化的數據序列化框架相比與等傳統的序列化工具它更小更快更簡
Google Protobuf 優點:
在谷歌內部長期使用, 產品成熟度高.
跨語言、支持多種語言, 包括 C++、Java 和 Python.
編碼后的消息更小, 更加有利于存儲和傳輸.
編解碼的性能非常高.
支持不同協議版本的前向兼容.
支持定義可選和必選字段.
Protobuf 的入門Protobuf 是一個靈活、高效、結構化的數據序列化框架, 相比與 xml 等傳統的序列化工具, 它更小、更快、更簡單.
Protobuf 支持數據結構化一次可以到處使用, 甚至跨語言使用, 通過代碼生成工具可以自動生成不同語言版本的源代碼, 甚至可以在使用不同版本的數據結構進程間進行數據傳遞, 實現數據結構前向兼容.
定義消息類型syntax = "proto3"; message SearchRequest { string query = 1; int32 page_number = 2; int32 result_per_page = 3; }
該文件的第一行指定使用 proto3 語法, 如果不寫的話表示 proto2.
分配字段編號string query = 1; 1 就是字段編號, 字段號主要用來標識二進制格式字段的. 1 到 15 字段號占一個字節. 16 到 2047 字段號需要兩個字節.
我們將對象轉換為報文的時候, 是按照字段編號進行報文封裝的; 我們接收到數據之后框架會幫我們按照字段號進行賦值.
不能使用數字19000到19999, 因為它們是為 Google Protobuf 保留的.
字段類型對應.proto Type | Notes | C++ Type | Java Type |
---|---|---|---|
double | double | double | |
float | float | float | |
int32 | 使用可變長度編碼, 對負數編碼效率低下 如果您的字段可能有負值, 則使用sint32代替. |
int32 | int |
int64 | 使用可變長度編碼, 對負數編碼效率低下 如果您的字段可能有負值, 則使用sint64代替. |
int64 | long |
uint32 | 使用可變長度編碼 | uint32 | int |
uint64 | 使用可變長度編碼 | uint64 long | |
sint32 | 使用可變長度編碼 有符號的int值這些編碼比常規int32更有效地編碼負數 |
uint32 | int |
sint64 | 使用可變長度編碼 有符號的int值這些編碼比常規int64更有效地編碼負數 |
int64 | long |
fixed32 | 四個字節, 如果值通常大于2的28次方, 則比uint32更有效 | uint32 | int |
fixed64 | 四個字節, 如果值通常大于2的56次方, 則比uint64更有效 | uint64 | long |
sfixed32 | 四個字節 | int32 | int |
sfixed64 | 四個字節 | int64 | long |
bool | bool | boolean | |
string | 字符串必須始終包含UTF-8編碼或7位ASCII文本 | string | String |
bytes | 字符串必須始終包含UTF-8編碼或7位ASCII文本 | string | ByteString |
對于字符串, 默認值是空字符串.
對于字節, 默認值為空字節.
對于bool, 默認值為false.
對于數字類型, 默認值為零.
對于枚舉, 默認值是第一個定義的枚舉值, 必須為0.
還請注意, 如果消息字段設置為默認值, 則該值將不會序列化.允許嵌套
Protocol Buffers 定義 message 允許嵌套組合成更加復雜的消息
message SearchResponse { repeated Result results = 1; } message Result { string url = 1; string title = 2; repeated string snippets = 3; }
更多的例子:
message SearchResponse { message Result { string url = 1; string title = 2; repeated string snippets = 3; } repeated Result results = 1; } message SomeOtherMessage { SearchResponse.Result result = 1; }
message Outer { // Level 0 message MiddleAA { // Level 1 message Inner { // Level 2 int64 ival = 1; bool booly = 2; } } message MiddleBB { // Level 1 message Inner { // Level 2 int32 ival = 1; bool booly = 2; } } }導入定義
可以在文件的頂部添加一個import語句:
import "myproject/other_protos.proto";未知字段
未知字段就是解析器無法識別的字段. 例如, 當服務端使用新消息發送數據, 客戶端使用舊消息解析數據, 那么這些新字段將成為舊消息中的未知字段.
在3.5和更高版本中, 未知字段在解析過程中被保留, 并包含在序列化中輸出.
Map 類型repeated 類型可以用來表示數組, Map 類型則可以用來表示字典.
mapmap_field = N; map projects = 3;
key_type 可以是任何 int 或者 string 類型(任何的標量類型, 具體可以見上面標量類型對應表格, 但是要除去 float、double 和 bytes)
枚舉值也不能作為 key.
key_type 可以是除去 map 以外的任何類型.
需要特別注意的是:
map 是不能用 repeated 修飾的.
map 迭代順序的是不確定的, 所以你不能確定 map 是一個有序的.
為 .proto 生成文本格式時, map 按 key 排序. 數字的 key 按數字排序.
從數組中解析或合并時, 如果有重復的 key, 則使用所看到的最后一個 key(覆蓋原則).從文本格式解析映射時, 如果有重復的 key, 解析可能會失敗.
Protocol Buffer 雖然不支持 map 類型的數組, 但是可以轉換一下, 用以下思路實現 maps 數組:
message MapFieldEntry { key_type key = 1; value_type value = 2; } repeated MapFieldEntry map_field = N;
上述寫法和 map 數組是完全等價的,所以用 repeated 巧妙的實現了 maps 數組的需求.
Protocol Buffer 命名規范message 采用駝峰命名法. message 首字母大寫開頭. 字段名采用下劃線分隔法命名.
message SongServerRequest { required string song_name = 1; }
枚舉類型采用駝峰命名法. 枚舉類型首字母大寫開頭. 每個枚舉值全部大寫, 并且采用下劃線分隔法命名.
enum Foo { FIRST_VALUE = 0; SECOND_VALUE = 1; }
每個枚舉值用分號結束, 不是逗號.
服務名和方法名都采用駝峰命名法. 并且首字母都大寫開頭.
service FooService { rpc GetSomething(FooRequest) returns (FooResponse); }常用方法
getDefaultInstance(): 返回單例實例, 它與 newBuilder().build() 實例相同
getDescriptor(): 返回類型的描述符. 包括具有哪些字段以及類型. 這可以與 Message 的反射方法一起使用, 例如getField().
parseFrom(...): 返回反序列化后的 Message. 注意不會拋出 UninitializedMessageException 和 InvalidProtocolBufferException 異常.
Message.Builder: 中的 mergeFrom() 放會將數據解析為此類型的消息, 并進行消息合并.
newBuilder(): 創建一個新的構建器.
Any類型允許包裝任意的message類型:
import "google/protobuf/any.proto"; message Response { google.protobuf.Any data = 1; }總結
message SubscribeReq { int32 subReqID = 1; string userName = 2; string productName = 3; string address = 4; }
可以通過 pack() 和 unpack()(方法名在不同的語言中可能不同)方法裝箱/拆箱,以下是Java的例子:
People people = People.newBuilder().setName("proto").setAge(1).build(); // protoc編譯后生成的message類 Response r = Response.newBuilder().setData(Any.pack(people)).build(); // 使用Response包裝people System.out.println(r.getData().getTypeUrl()); // type.googleapis.com/example.protobuf.people.People System.out.println(r.getData().unpack(People.class).getName()); // protoOneof
如果你有一些字段同時最多只有一個能被設置, 可以使用 oneof 關鍵字來實現, 任何一個字段被設置, 其它字段會自動被清空(被設為默認值):
message SampleMessage { oneof test_oneof { string name = 4; SubMessage sub_message = 9; } }默認值
比如我們創建了上面的消息類型, 我們在代碼中設置 builder.setSubReqID(0); 為 0, 零是數值類型的默認值; 所以我們會看到序列化后的數據中, 沒有對此字段進行序列化.
byte[] arry = builder.build().toByteArray();
arry 長度為 0. 對于字段類型是 string 類型的也是一樣的; 也就是說顯示賦值默認值也不會對其進行序列化.
保留字段message SubscribeReq { reserved 2; int32 subReqID = 1; string userName = 2; string productName = 3; string address = 4; }
顧名思義, 就是此字段會被保留可能在以后會使用此字段. 使用關鍵字 reserved 表示我要保留字段數 2.
上面代碼我們在生成 Java 文件的時候會出現 ubscribeReqPeoro.proto: Field "userName" uses reserved number 2 錯誤信息, 所以我們需要將 string userName = 2; 注釋, 或者刪除.
保留后我們無法對其設置或序列化和反序列化.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72796.html
摘要:是一個面向字節流的協議,它是性質是流式的,所以它并沒有分段。可基于分隔符解決。編解碼的主要目的就是為了可以編碼成字節流用于在網絡中傳輸持久化存儲。 showImg(https://segmentfault.com/img/remote/1460000015895049); 前言 記得前段時間我們生產上的一個網關出現了故障。 這個網關邏輯非常簡單,就是接收客戶端的請求然后解析報文最后發送...
摘要:等之所以支持跨語言,是因為他們自己定義了一套結構化數據存儲格式,如的,用于編解碼對象,作為各個語言通信的中間協議。 前段時間覺得自己一直用別人的框架,站在巨人的肩膀上,也該自己造造輪子了 一時興起 就著手寫起了RPC框架 這里寫了系列博客拿給大家分享下 這篇是開篇的思路篇 項目最終的代碼放在了我的github上https://github.com/wephone/Me... 歡迎sta...
摘要:結構作為服務端作為序列化數據的協議前端通訊演示地址服務端實現啟動類長連接示例主線程組從線程組請求的解碼和編碼把多個消息轉換為一個單一的或是,原因是解碼器會在每個消息中生成多個消息對象主要用于處理大數據流,比如一個大小的文件如果你直接傳輸肯定 結構 netty 作為服務端 protobuf 作為序列化數據的協議 websocket 前端通訊 演示 GitHub 地址 showImg(...
摘要:結構作為服務端作為序列化數據的協議前端通訊演示地址服務端實現啟動類長連接示例主線程組從線程組請求的解碼和編碼把多個消息轉換為一個單一的或是,原因是解碼器會在每個消息中生成多個消息對象主要用于處理大數據流,比如一個大小的文件如果你直接傳輸肯定 結構 netty 作為服務端 protobuf 作為序列化數據的協議 websocket 前端通訊 演示 GitHub 地址 showImg(...
閱讀 1751·2023-04-25 22:42
閱讀 2201·2021-09-22 15:16
閱讀 3485·2021-08-30 09:44
閱讀 484·2019-08-29 16:44
閱讀 3303·2019-08-29 16:20
閱讀 2511·2019-08-29 16:12
閱讀 3386·2019-08-29 16:07
閱讀 665·2019-08-29 15:08