前言 Protocol Buffers (下麵簡稱PB)是一種輕便高效的結構化數據存儲格式,可以用於結構化數據串列化,很適合做數據存儲或 RPC 數據交換格式。它可用於通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。它支持多種語言,比如C++,Java,C ,Python, ...
前言
Protocol Buffers (下麵簡稱PB)是一種輕便高效的結構化數據存儲格式,可以用於結構化數據串列化,很適合做數據存儲或 RPC 數據交換格式。它可用於通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。它支持多種語言,比如C++,Java,C#,Python,JavaScript等等。目前它的最新版本是3.0.0。與PB經常相提並論的也是Google推出的FlatBuffers(下麵簡稱FB)。有關PB和FB性能和語義等方面的區別,這裡就不展開描述了。如果有興趣,可以參閱下麵的信息:
目前很多公司在一些高性能的通信場景下,會越來越多的選擇用PB或者FB來替代我們常用的Json。比如說Windows Phone的微信的SDK就用到了。
反編譯微信SDK
PB對C#官方的支持是從3.0開始的,之前的1.0和2.0的版本都能找到一些非官方的版本。我們先反編譯一下微信的SDK,看下它具體是什麼版本的。
首先,我們從微信的官網下載SDK:
登陸微信開發平臺,進入資源中心,選擇WP8資源下載,點擊下載。
然後下載我們的反編譯工具ILSpy。
解壓下載完成的ILSpy和SDK包,用ILSpy.exe打開MicroMsgSDK.dll。
我們暫時先不管這個結構到底是怎麼來的,我們可以看到反編譯出來的文件帶了ProtoGen的版本號,我們嘗試從Github上找到這個版本號的代碼。
編譯ProtoBuffer源碼
我們先打開官方的C#版本的PB的源碼頁面:地址。
可以看到官方地址只保留了3.0的版本,對於舊的2.0版本的代碼在jskeet的賬號下,
我們點開這個倉庫,然後找到它的Release頁面:
我們找到2.3.0.277的源碼並下載到本地。
解壓文件,我們看到Build文件夾下有一堆編譯用的腳本:
雙擊運行buildAll.bat(此處應確保本機已經安裝了Visual Studio 2008及以上版本),然後等待編譯完成。
嘗試使用源碼中的Proto文件生成cs代碼
我們找到ProtoGen項目中生成的exe文件,嘗試將它放到命令行中運行:
它提示我們找不到protoc.exe程式。我們回到源碼的根目錄會發現有一個lib的文件夾,裡面有一個protoc.exe的程式。所以我們嘗試吧ProtoGen項目的所有生成文件拷貝到lib下。
繼續嘗試運行我們的ProtoGen程式。
這回對了,我們嘗試把源碼下的protos文件夾下的三個子文件夾拷貝到我們的lib目錄下。
我們嘗試輸入如下內容:
protogen --proto_path==protos protos/tutorial/addressbook.proto
又得到一個錯誤信息:
提示我們找不到依賴,我們嘗試打開proto文件:(有關PB的語法請參閱:http://www.cnblogs.com/stephen-liu74/archive/2013/01/02/2841485.html)
package tutorial;
import "google/protobuf/csharp_options.proto";
option (google.protobuf.csharp_file_options).namespace = "Google.ProtocolBuffers.Examples.AddressBook";
option (google.protobuf.csharp_file_options).umbrella_classname = "AddressBookProtos";
option optimize_for = SPEED;
message Person {
required string name = 1;
required int32 id = 2; // Unique ID number for this person.
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;
}
// Our address book file is just one of these.
message AddressBook {
repeated Person person = 1;
}
我們可以看到導入了google/protobuf/csharp_options.proto文件,我們回頭看protogen的命令參數中有一個import的標記,我們嘗試添加:
protogen --proto_path==protos protos/tutorial/addressbook.proto --include_imports=google/protobuf/csharp_options.proto
沒有任何錯誤,並且我們在lib的目錄下發現了生成的cs文件。
從cs文件反推proto文件
我們打開AddressBookProtos文件,閱讀源碼發現:
只有兩個非靜態類,與我們Proto文件中的Person和AddressBook對應:
Person類中又有一個嵌套的枚舉和類,與PhoneType和PhoneNumber對應:
我們有發現,在類的IsInitialized中,Name和Id等required的有是否有值得判斷,所以我們能區分去required和optional
其他依賴信息,我們可以通過引用來查找。
從反編譯的微信文件中反推proto文件
我們以BaseReqP為例。首先,沒有using,所以我們確定沒有其他的Proto文件的依賴。我們只發現一個類,所以說明它只有一條message,名稱就是BaseReqP,然後包名是MicroMsg.sdk.protobuf。
我們知道message的所有欄位是需要標記數字的:
從這裡我們又反推出,message有兩個欄位:Transaction和Type,它們類型分別是string和uint。
接下來我們推是否是必須的。找到我們的IsInitialized:
從這裡我們就知道了兩個欄位都是必須的。所以綜合上述信息,我們可以寫出的proto文件如下:
package MicroMsg.sdk.protobuf;
message BaseReqP {
required uint32 Type = 1;
required string Transaction = 2;
}
小結
本篇內容簡要介紹了ProtoBuffer的文件如何生成C#文件,並簡單的舉例如何從C#文件反推Proto文件。
參考信息
- FlatBuffers Documentation
- Google Protocol Buffer 的使用和原理
- Protobuf Source
- protocol-buffers documentation
- Google序列化庫FlatBuffers 1.1發佈,及與protobuf的比較
- FlatBuffers與protobuf性能比較
- Protocol Buffer使用簡介
- Protocol Buffer技術詳解(語言規範)