从微信SDK看ProtoBuffer文件的生成

摘要:
前言ProtocolBuffers是一种可移植且高效的结构化数据存储格式,可用于结构化数据序列化,非常适合数据存储或RPC数据交换格式。谷歌推出的FlatBuffers经常与PB进行比较。为了编译ProtoBuffer源代码,我们首先打开PB源页的官方C#版本:address。因此,我们尝试将ProtoGen项目的所有生成文件复制到lib。为了从反编译的微信文件中反转原型文件,让我们以BaseReqP为例。首先,没有使用,因此我们确保不依赖其他Proto文件。
前言

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

参考信息

免责声明:文章转载自《从微信SDK看ProtoBuffer文件的生成》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇研发项目风险因素差异性如何导出远程oracle数据库中的表结构下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

离线搭建安卓环境 adt

1、下载SDK。到安卓官网http://developer.android.com/sdk/index.html 下载SDK,选这个如图1,因为这个是adt-bundle-windows-x86的压缩包,里面包含eclipse和SDK,eclipse它已经集成好了ADT。其实这个包下载的并不是很全,不全的后面还是要在线下载,但是相对的时间会短点!(这也是后...

vscode 无法查看完整源码,环境是wsl2+ubunu,语言java

首先你是否安装了插件 Language support for Java ™ for Visual Studio Code2.然后在终端输入 sudo apt-get update 3.输入sudo apt install openjdk-你的版本-source 4.重新打开vscode,好了。   ✖...

源码安装LNMP与搭建Zabbix

系统环境:CentOS release 6.5 (Final) 搭建Zabbix 3.0对PHP环境要求>= 5.4 一、下载NMP的软件包: N:wget http://nginx.org/download/nginx-1.8.0.tar.gz P:wget http://cn2.php.net/distributions/php-5.6.28.t...

【MyBatis源码分析】Configuration加载(下篇)

元素设置 继续MyBatis的Configuration加载源码分析: 1 private void parseConfiguration(XNode root) { 2 try { 3 Properties settings = settingsAsPropertiess(root.evalNode("settings"))...

详解S7源码3-COTP and TPKT

连接 S7COMM简介 https://www.anquanke.com/post/id/186099 OSI layer    Protocol Application Layer    S7 communication Presentation Layer    S7 communication(COTP) Session Layer    S7 co...

Netty之EventLoop-netty学习笔记(11)-20210813

线程模型概述 基本的线程池化模式可以描述为: 从池的空闲线程列表中选择一个 Thread,并且指派它去运行一个已提交的任务(一个Runnable 的实现);当任务完成时,将该 Thread 返回给该列表,使其可被重用。 虽然池化和重用线程相对于简单地为每个任务都创建和销毁线程是一种进步,但是它并不能 消除由上下文切换所带来的开销,其将随着线程数量的增加很快...