从微信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文件。

参考信息

相关文章
相关标签/搜索