從微信SDK看ProtoBuffer文件的生成


前言

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:

Image

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

然后下載我們的反編譯工具ILSpy

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

Image

我們暫時先不管這個結構到底是怎么來的,我們可以看到反編譯出來的文件帶了ProtoGen的版本號,我們嘗試從Github上找到這個版本號的代碼。

編譯ProtoBuffer源碼

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

可以看到官方地址只保留了3.0的版本,對於舊的2.0版本的代碼在jskeet的賬號下,

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文件。

參考信息


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM