從微信SDK看ProtoBuffer文件的生成

前言

Protocol Buffers (下面簡稱PB)是一種輕便高效的結構化數據存儲格式,能夠用於結構化數據串行化,很適合作數據存儲或 RPC 數據交換格式。它可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。它支持多種語言,好比C++,Java,C#,Python,JavaScript等等。目前它的最新版本是3.0.0。與PB常常相提並論的也是Google推出的FlatBuffers(下面簡稱FB)。有關PB和FB性能和語義等方面的區別,這裏就不展開描述了。若是有興趣,能夠參閱下面的信息:html

目前不少公司在一些高性能的通訊場景下,會愈來愈多的選擇用PB或者FB來替代咱們經常使用的Json。好比說Windows Phone的微信的SDK就用到了。linux

反編譯微信SDK

PB對C#官方的支持是從3.0開始的,以前的1.0和2.0的版本都能找到一些非官方的版本。咱們先反編譯一下微信的SDK,看下它具體是什麼版本的。git

首先,咱們從微信的官網下載SDK:github

Image

登錄微信開發平臺,進入資源中心,選擇WP8資源下載,點擊下載。微信

而後下載咱們的反編譯工具ILSpy微信開發

解壓下載完成的ILSpy和SDK包,用ILSpy.exe打開MicroMsgSDK.dll。工具

Image

咱們暫時先無論這個結構究竟是怎麼來的,咱們能夠看到反編譯出來的文件帶了ProtoGen的版本號,咱們嘗試從Github上找到這個版本號的代碼。性能

編譯ProtoBuffer源碼

咱們先打開官方的C#版本的PB的源碼頁面:地址ui

能夠看到官方地址只保留了3.0的版本,對於舊的2.0版本的代碼在jskeet的帳號下,this

Image

咱們點開這個倉庫,而後找到它的Release頁面:

Image

咱們找到2.3.0.277的源碼並下載到本地。

解壓文件,咱們看到Build文件夾下有一堆編譯用的腳本:

Image

雙擊運行buildAll.bat(此處應確保本機已經安裝了Visual Studio 2008及以上版本),而後等待編譯完成。

嘗試使用源碼中的Proto文件生成cs代碼

咱們找到ProtoGen項目中生成的exe文件,嘗試將它放到命令行中運行:
Image

它提示咱們找不到protoc.exe程序。咱們回到源碼的根目錄會發現有一個lib的文件夾,裏面有一個protoc.exe的程序。因此咱們嘗試吧ProtoGen項目的全部生成文件拷貝到lib下。
繼續嘗試運行咱們的ProtoGen程序。

Image

這回對了,咱們嘗試把源碼下的protos文件夾下的三個子文件夾拷貝到咱們的lib目錄下。

咱們嘗試輸入以下內容:

protogen --proto_path==protos protos/tutorial/addressbook.proto

又獲得一個錯誤信息:

Image

提示咱們找不到依賴,咱們嘗試打開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文件。
Image

從cs文件反推proto文件

咱們打開AddressBookProtos文件,閱讀源碼發現:

  • 只有兩個非靜態類,與咱們Proto文件中的Person和AddressBook對應:
    Image

  • Person類中又有一個嵌套的枚舉和類,與PhoneType和PhoneNumber對應:
    Image

  • 咱們有發現,在類的IsInitialized中,Name和Id等required的有是否有值得判斷,因此咱們能區分去required和optional
    Image

其餘依賴信息,咱們能夠經過引用來查找。

從反編譯的微信文件中反推proto文件

咱們以BaseReqP爲例。首先,沒有using,因此咱們肯定沒有其餘的Proto文件的依賴。咱們只發現一個類,因此說明它只有一條message,名稱就是BaseReqP,而後包名是MicroMsg.sdk.protobuf。
咱們知道message的全部字段是須要標記數字的:
Image

從這裏咱們又反推出,message有兩個字段:Transaction和Type,它們類型分別是string和uint。
接下來咱們推是不是必須的。找到咱們的IsInitialized:
Image
從這裏咱們就知道了兩個字段都是必須的。因此綜合上述信息,咱們能夠寫出的proto文件以下:

package MicroMsg.sdk.protobuf;

message BaseReqP {
    required uint32 Type = 1;
    required string Transaction = 2;
}

小結

本篇內容簡要介紹了ProtoBuffer的文件如何生成C#文件,並簡單的舉例如何從C#文件反推Proto文件。

參考信息

相關文章
相關標籤/搜索