生活随笔
收集整理的這篇文章主要介紹了
protobuf 语法浅析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
Protobuf 為什么用Protobuf Buffer 跨語言平臺編程,使用SOAP的話,該方式是使用xml的方式傳輸,會大大增加網絡的IO,而且xml的解析復雜,降低報文的解析性能。
定義一個Protobuf消息 message LogonReqMessage{required int64 actID=1;required string passwd=2;
}
關鍵說明:
message是消息的關鍵字 LogonReqMessage是消息名字,相當于java的類名 required前綴表示該字段未必要字段,序列化前后必須賦值 的字段。protobuf還存在兩個類似的關鍵字optional和repeated主要用于表示數組字段。 int64和string表示長整型和字符串類型的消息字段,在protobuf中存在一張類型對照表,即protobuf類型與其他語言的類型對照。 actID和passwd分別表示消息的字段名,等同于java中的域名變量名。 標簽數字1和2表示不同的字段在序列化前后的二進制中的布局位置。在本例中,passwd字段編碼后的數據一定位于actID后,該值在同一個message中不能重復 。對于protobuf而言,標簽1到15的字段在編碼的時候是可以得到優化的(標簽值和類型信息只占一個byte,標簽范圍16到2047占兩個byte),protobuf可支持的字段數量是$2^{29}-1$。因此,應該將repeated類型的字段標簽未與1~15 ,節省編碼后的字節數量。 定義第二個protobuf消息 enum UserStatus{OFFLINE=0;ONLINE=1;
}message UserInfo{required int64 actID=1;required string name=2;required UserStatus=3;
}
關鍵說明:
enum是枚舉類型的關鍵字,等同于java里面的enum UserStatus為枚舉的名字 和java一樣枚舉之間的分隔符是分好;而不是逗號, OFFLINE和ONLINE表示枚舉值 0和1表示枚舉所對應的實際 整型值,可為任意整型值,無需從0開始。 定義第三個protobuf消息 enum UserStatus{OFFLINE=0;ONLINE=1;
}message UserInfo{required int64 actID=1;required string name=2;required UserStatus=3;
}message LogonRespMessage{required LoginResult logonResult = 1;required UserInfo userInfo = 2;
}
關鍵說明:
LogonRespMessage消息定義中包含另外一個消息類型作為其字段,如UserInfo userInfo; 上例的UserInfo和LogonRespMessage被定義在同一個.proto文件中,那么怎么包含其他proto文件中的message呢?ProtoBuf提供關鍵字import將其他proto文件的message引入到當前proto文件中。例如Import "myproject/CommonMessages.proto" 限定符號 每個消息必須有一個字段是required類型的字段。 每個消息包含0個或多個optional類型的字段。 repeated表示的字段可以包含0個或多個數據 ,有別于java的數組,因為java數組中至少包含一個元素 。 如果打算在原有消息協議中添加新的字段,同時保證老的字段能正常的讀取寫入,那么新添加的字段必須是optional或者repeated類型的。 proto類型對照表 .proto Type|Notes|C++ Type|Java Type -|-|-|- double||double|double float||float|float int32|"Uses variable-length encoding. Inefficient for encoding negative numbers ¨C if your field is likely to have negative values use sint32 instead."|int32|int int64|"Uses variable-length encoding. Inefficient for encoding negative numbers ¨C if your field is likely to have negative values use sint64 instead."|int64|long uint32|Uses variable-length encoding.|uint32|int uint64|Uses variable-length encoding.|uint64|long sint32|Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int32s.|int32|int sint64|Uses variable-length encoding. Signed int value. These more efficiently encode negative numbers than regular int64s.|int64|long fixed32|Always four bytes. More efficient than uint32 if values are often greater than 228.|uint32|int fixed64|Always eight bytes. More efficient than uint64 if values are often greater than 256.|uint64|long sfixed32|Always four bytes.|int32|int sfixed64|Always eight bytes.|int64|long bool||bool|boolean string|A string must always contain UTF-8 encoded or 7-bit ASCII text.|string|String bytes|May contain any arbitrary sequence of bytes.|string|ByteString
protobuf消息升級原則 不要修改已經存在字段的標簽號 任何新添加的字段必須是optional或者repeated限定符,否則無法保證新老程序在互傳消息的時候消息的兼容性。 在原有消息中,不能移除已經存在的required字段,optional和repeated類型字段可以移除,但是他們之前使用的標簽不能使用了。 int32,uint32,int64,uint64和bool等類型之間是兼容的,sint32和sint64是兼容的,stirng和byte是兼容的,fixed32和sfixed32是兼容的,fixed64和sfixed64是兼容的,如果想修改原有字段類型,為了保證兼容性,只能將其修改為原有類型兼容的類型,否則打破新老消息格式的兼容性。 optional和repeated限定符是相互兼容的。 packages 可以在.proto文件中定義包名,如:package abc.lypgone,該包名生成c++時,替換成名字空間,而java為java的包名。
options protobuf 在.proto文件中定義一些常用的選項,這樣protobuf可以幫助我們生成更匹配的目標語言代碼。
protobuf的內置選項分為三個等級:
文件級,這樣的選項影響當前文件的所有消息和枚舉。 消息級,這樣的選項僅影響某個消息及其包含的所有字段。 字段級,這樣的選項近影響某個字段。 常用的protobuf選項有:
option java_package="com.companyname.projectname"; java_package 是文件級的選項,指定讓生成的java代碼的包名為該選項的值;與此同時,輸出的文件也自動輸出到對應包目錄下(上例的com/companyname/projectname目錄下),該選項對C++沒有影響。 option java_outer_classname="LYPhoneMessage"; java_outer_classname是文件級別的選項,指定生成的java代碼的外部類名稱。如果沒有指定,java代碼的外部類名稱為當前文件的文件名部分,同時將文件名轉為駝峰格式,如my_project.proto,那么該文件的外部類名為MyProject,該選項對C++代碼無影響。 注意,由于一個java文件只能有一個外部類或者外部接口,所以.proto文件中的message定義的消息均為外部類的內部類,這樣才能將這些消息定義到一個文件中。c++沒有此限制。
option optimize_for = LITE_RUNTIME; optimize_for 是文件級選項,是protobuf優化選項。該選項又分為3個等級: SPEED:表示生成的代碼運行效率高 ,但是由此生成的代碼編譯后會占用更多的空間 。 CODE_SIZE: 和SPEED恰恰相反,代碼運行效率較低,但是由此生成的代碼編譯后會占用更少的空間 ,通常用于資源有限的平臺,如Mobile。 LITE_RUNTIME: 生成的代碼執行效率高 ,同時生成代碼編譯后的所占用的空間也是非常少 。這是以犧牲Protocol Buffer提供的反射功能為代價的 。因此我們在C++中鏈接Protocol Buffer庫時僅需鏈接libprotobuf-lite,而非libprotobuf。在Java中僅需包含protobuf-java-2.4.1-lite.jar,而非protobuf-java-2.4.1.jar 對于LITE_MESSAGE選項而言,其生成的代碼均將繼承自MessageLite,而非Message。
[pack = true]: 因為歷史原因,對于數值型的repeated字段,如int32、int64等,在編碼時并沒有得到很好的優化,然而在新近版本的Protocol Buffer中,可通過添加[pack=true]的字段選項,以通知Protocol Buffer在為該類型的消息對象編碼時更加高效。如:repeated int32 samples = 4 [packed=true]。 注:該選項僅適用于2.3.0 以上的Protocol Buffer
[default = default_value]: optional類型的字段,如果在序列化時沒有被設置,或者是老版本的消息中根本不存在該字段,那么在反序列化該類型的消息是,optional的字段將被賦予類型相關的缺省值 ,如bool被設置為false,int32被設置為0。Protocol Buffer也支持自定義的缺省值 ,如:optional int32 result_per_page = 3 [default = 10]。 命令行編譯工具 protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR path/to/file.proto
這里將給出上述命令的參數解釋。
protoc為Protocol Buffer提供的命令行編譯工具 。 --proto_path等同于-I選項,主要用于指定待編譯的.proto消息定義文件所在的目錄 ,該選項可以被同時指定多個。 --cpp_out選項表示生成C++代碼 ,--java_out表示生成Java代碼 ,--python_out則表示生成Python代碼 ,其后的目錄為生成后的代碼所存放的目錄。 path/to/file.proto表示待編譯的消息定義文件 。 注:對于C++而言,通過Protocol Buffer編譯工具,可以將每個.proto文件生成出一對.h和.cc的C++代碼文件。生成后的文件可以直接加載到應用程序所在的工程項目中。如:MyMessage.proto生成的文件為MyMessage.pb.h和MyMessage.pb.cc。
轉載于:https://my.oschina.net/hgfdoing/blog/712889
總結
以上是生活随笔 為你收集整理的protobuf 语法浅析 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。