之前使用 protobuf 2.5 的版本来定制和读取表格,为了适应后端 golang 的工具选型,需要将前端的的一些库和工具都升到 3.x 的版本,例如, C# 中要使用 protobuf 需要引入一个编译好的 protobuf-net.dll 库文件。
Protobuf 3.4.x :
1.资源下载:
protobuf
源码:这里直接选择最新的 Protocol Buffers v3.4.0 ,然后下载源码 Source code (zip) ,至于详细关于 protobuf 3.x 版本的特点可以查看 项目中使用protobuf 3.0 ;
gmock
和gtest
工具:E:\Protobuf\3.4.0\tools>git clone -b "3.4.x" https://github.com/google/protobuf.git E:\Protobuf\3.4.0\tools>cd protobuf E:\Protobuf\3.4.0\tools\protobuf>git clone -b release-1.7.0 https://github.com/google/googlemock.git gmock E:\Protobuf\3.4.0\tools\protobuf>cd gmock E:\Protobuf\3.4.0\tools\protobuf\gmock>git clone -b release-1.7.0 https://github.com/google/googletest.git gtest
以上两步可以直接通过编写一个自动化脚本来完成,使用不同版本只需修改版本号即可:
::参考文章 https://github.com/google/protobuf/blob/master/cmake/README.md
::默认当前操作系统已安装 git 和 cmake,并配置好了环境变量
echo off & color 0A
::设置所需要的Protobuf版本,最新版本可以在github上查到 https://github.com/google/protobuf
set PROTOBUF_VESION="3.4.x"
echo %PROTOBUF_VESION%
set PROTOBUF_PATH="protobuf_%PROTOBUF_VESION%"
echo %PROTOBUF_PATH%
::从githug上拉取protobuf源代码
git clone -b %PROTOBUF_VESION% https://github.com/google/protobuf.git %PROTOBUF_PATH%
::从github上拉取gmock
cd %PROTOBUF_PATH%
git clone -b release-1.7.0 https://github.com/google/googlemock.git gmock
::从github上拉取gtest
cd gmock
git clone -b release-1.7.0 https://github.com/google/googletest.git gtest
pause
CMake
工具:直接到 CMake 官网 下载最新版本的编译工具 cmake-3.9.4-win64-x64.msi 。
2.源码编译:
旧版本(protobuf 2.5)里面有一个 vsprojects 的目录,直接使用 VS 编辑器打开即可编译,新版本(protobuf 3.x)没有此目录,且改用 CMake 工具来编译源码,使用 CMake 工具来生成 VS 工程,(注:要顺利执行编译需要给 VS 安装 C++ 插件,否则 cmake 编译时会提示找不到 C compiler 和 C++ Compiler:The C compiler identification is unknown,The CXX compiler identification is unknown)具体步骤如下:
安装
CMake
,并将其安装目录下 bin 文件的路径添加到系统环境配置信息中的Path
中(方便命令行中全局调用此工具);在上面下载好的
protobuf_3.4.x
文件夹同级目录下新建一个install
目录用于存储编译完成后 include 和 lib 等文件;打开
cmake-gui
,设置两个目录地址:where is the source code:
是E:\Protobuf\3.4.0\tools\protobuf_3.4.x
中的cmake
目录;where to build the binaries:
自己创建的地址E:\Protobuf\3.4.0\tools\install
,用于存储编译结果的库资源;点击
Configure
配置要创建的 VS 工程适用的版本,这里我选择的是"Visual Studio 14 2015 Win64"
,然后点击Finish
开始进行配置,配置完成会输出"Configuring done"
:点击
Generate
生成对应的 VS 工程,完成则输出"Generating done"
:点击
Open Project
即会在 VS 中打开工程,在编译环境设置中选择Release
和x64
,然后在解决方案资源管理器
窗口中选中跟目录,右键
-生成解决方案
:编译成功会有如下输出:
... 13>------ 已启动生成: 项目: ALL_BUILD, 配置: Release x64 ------ 14>------ 已跳过生成: 项目: check, 配置: Release x64 ------ 14>没有为此解决方案配置选中要生成的项目 13> Building Custom Rule E:/Protobuf/3.4.0/tools/protobuf_3.4.x/cmake/CMakeLists.txt 13> CMake does not need to re-run because E:/Protobuf/3.4.0/tools/install/CMakeFiles/generate.stamp is up-to-date. 15>------ 已跳过生成: 项目: INSTALL, 配置: Release x64 ------ 15>没有为此解决方案配置选中要生成的项目 ========== 生成: 成功 13 个,失败 0 个,最新 0 个,跳过 2 个 ==========
在之前自己创建的
install
目录下会生成一个Release
目录,从中可以获取protoc.exe
解释器。
参考 protobuf 官方 API ,将 .proto
转为 .cs
只需一个指令:
protoc --csharp_out=(.cs输出目录) --proto_path=(.proto目录) (.proto名称)
Protobuf-net :
上面步骤完成之后,我们只是得到了目标文件之一的 protoc.exe
,假如要在 Unity 的 C# 层使用的话,还需要用到 protobuf-net
工具中的 protogen.exe
和 protobuf-net.dll
这些工具,因为 protoc.exe
转化得到的 .cs 脚本 Unity 无法实现解析,只能解析 protobuf-net
转化得到的 .cs 脚本。
下载源码 protobuf-net ,这里需要安装 Visual Studio 2017 才能打开工程文件,当然也可以直接使用 VS 中的 NuGet 工具来下载工程,操作步骤如下:
工具
—>NuGet 包管理器
—>程序包管理器控制台
打开指令控制台;然后在 NuGet 官网 搜索制定版本的程序安装包的下载指令,在控制台中输入,这里输入:
Install-Package protobuf-net -Version 2.3.2
这里我还是直接使用 VS 2017 打开
protobuf-net.sln
,选择Release
然后生成解决方案,输出如下则表示编译成功:... ========== 生成: 成功 6 个,失败 0 个,最新 0 个,跳过 0 个 ==========
打开工程文件中的
src\protogen\bin\Release\net40
文件夹,可得到所有的工具;protobuf-net 还提供了 protogen在线生成脚本工具 ,可以在线校验本地生成结果是否正确。
然而,我出现的问题与这篇中的问题一致 Unity中使用ProtoBuff3.0,与netty服务器通信的粘包、拆包处理(一)
,问题在于:unity支持的.net版本是2.0和3.5,protobuf-net最新支持的是.NET Framework 4.0+的,官网上说v2.1.0的版本支持.NET Framework 2.0/3.0/3.5 ,但是一直安装不成功,不知道是哪里编译设置的问题,干脆就不瞎倒腾了。
protobuf3-for-unity :
所以,最后我也选择使用 protobuf3-for-unity 的方案来实现 C# 层面的协议解析中序列化和反序列化的库:
将编译好的
Google.Protobuf.dll
动态库放在Assets/Plugins
目录下;使用
protoc.exe
得到 C# 脚本:protoc --csharp_out=(.cs输出目录) --proto_path=(.proto存放目录) (当前.proto文件名称)
解析示例:
// 序列化 TvTEnvironment environment = new TvTEnvironment(); environment.Id = 20; environment.PopulationValue = 66; MemoryStream stream = new MemoryStream(); environment.WriteTo(stream); byte[] bytes = stream.ToArray(); // 反序列化 TvTEnvironment environment1 = TvTEnvironment.Parser.ParseFrom(bytes);
假如要使用泛型封装,可以参考下面:
public static IMessage Deserialize(MessageParser _type,byte[] byteData) { Stream stream = new MemoryStream(byteData); if(stream != null){ IMessage t = _type.ParseFrom(stream); stream.Close(); return t; } stream.Close(); return default(IMessage); } public static byte[] Serialize(IMessage _data) { MemoryStream stream = new MemoryStream(); if(stream != null){ _data.WriteTo(stream); byte[] bytes = stream.ToArray(); stream.Close(); return bytes; } stream.Close(); return null; }
使用泛型接口:
TvTEnvironment environment = new TvTEnvironment(); environment.Id = 20; environment.PopulationValue = 66; // 序列化 var datas = Serialize(environment); // 反序列化 TvTEnvironment data = (TvTEnvironment)Deserialize(TvTEnvironment.Parser,datas);