在我们编程的时候我们不仅仅要对一个字符串作为信息传输,有时候可能要将一个对象的相关信息进行传输,比如名字,分数,等级,位置,旋转等信息进行传输。分开传递工作量可能比较大。我们就可以考虑是不是可以将一个对象整体尽心传输。
protobuf是google的一个开源项目,protobuf可以很方便的将一个对象进行序列化,而且相对来说体积较小。
源代码下载地址:https://github.com/mgravell/protobuf-net
开源项目地址如下:https://code.google.com/p/protobuf-net/ ,下载解压后的目录如下所示,每个文件夹的详细介绍都在最后一个txt文件里面了。
ProtoGen是用来根据***.proto文件生成对应的***.cs文件的。
.proto可以直接通过记事本编写。
基本语法:
一 基本说明
结构定义文件为.proto,
可以使用import包含另一个.proto文件,
注释使用//
package 命名空间
message 类
二 语法
字段限制
required: 必须赋值的字符
optional: 可有可无的字段,可以使用[default = xxx]配置默认值
repeated: 可重复变长字段,类似数组
tag
每个字段都有独一无二的tag
tag 1-15是字节编码,16-2047使用2字节编码,所以1-15给频繁使用的字段
类型
系统默认值:
string默认为空字符串;
bool默认为false;
数值默认为0;
enum默认为第一个元素
enum PhoneType { // 定义枚举类型,生成Person_PhoneType类型
MOBILE = 0;
HOME = 1;
WORK = 2;
}
proto文件示例
syntax = "proto2"; // 定义语法类型,通常proto3好于proto2,proto2好于proto1
package tutorial; // 定义作用域
message Person { // 生成类class Person : public ::google::protobuf::Message
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType { // 定义枚举类型,生成Person_PhoneType类型
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber { // 生成Person_PhoneNumber类
required string number = 1;
optional PhoneType type = 2 [default = HOME]; // 值必须是枚举类型中的一个
}
repeated PhoneNumber phones = 4;
}
message AddressBook {
repeated Person people = 1;
}
以下是protogen工具,使用此工具可以很方便的将.proto文件转化成cs文件
使用命令可以通过cmd执行protogen.exe得到相关执行命令
例如:
生成单个文件比较简单
如果是多个文件的话执行可能相对麻烦,我们可以使用批处理
@echo off
::协议文件路径, 最后不要跟“\”符号
set SOURCE_FOLDER=D:\CodesStorage\UnityPrejects\YYSever\ServerProtocol\Sources
::C#编译器路径
set CS_COMPILER_PATH=E:\SoftWares\WorkSofts\protogen\protogen.exe
::C#文件生成路径, 最后不要跟“\”符号
set CS_TARGET_PATH=D:\CodesStorage\UnityPrejects\YYSever\ServerProtocol\Protocols
::删除之前创建的文件
del %CS_TARGET_PATH%\*.* /f /s /q
::遍历所有文件
for /f %%i in ('dir /b "%SOURCE_FOLDER%\*.proto"') do (
::生成 C# 代码
echo %CS_COMPILER_PATH% -i:%%i -o:%CS_TARGET_PATH%\%%~ni.cs
%CS_COMPILER_PATH% -i:%%i -o:%CS_TARGET_PATH%\%%~ni.cs
)
echo Tell You Created Protoccl Success!!
pause
以上工作完毕之后,我们可以测试相关此工具了。
测试:
proto文件
package ServerProtocol.Protocols;
message Student
{
required string name = 1;
optional int32 id = 2;
repeated 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;
}
生成cs文件
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
// Generated from: Student.proto
namespace ServerProtocol.Protocols
{
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"Student")]
public partial class Student : global::ProtoBuf.IExtensible
{
public Student() {}
private string _name;
[global::ProtoBuf.ProtoMember(1, IsRequired = true, Name=@"name", DataFormat = global::ProtoBuf.DataFormat.Default)]
public string name
{
get { return _name; }
set { _name = value; }
}
private int _id = default(int);
[global::ProtoBuf.ProtoMember(2, IsRequired = false, Name=@"id", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
[global::System.ComponentModel.DefaultValue(default(int))]
public int id
{
get { return _id; }
set { _id = value; }
}
private readonly global::System.Collections.Generic.List<string> _email = new global::System.Collections.Generic.List<string>();
[global::ProtoBuf.ProtoMember(3, Name=@"email", DataFormat = global::ProtoBuf.DataFormat.Default)]
public global::System.Collections.Generic.List<string> email
{
get { return _email; }
}
private readonly global::System.Collections.Generic.List<ServerProtocol.Protocols.Student.PhoneNumber> _phone = new global::System.Collections.Generic.List<ServerProtocol.Protocols.Student.PhoneNumber>();
[global::ProtoBuf.ProtoMember(4, Name=@"phone", DataFormat = global::ProtoBuf.DataFormat.Default)]
public global::System.Collections.Generic.List<ServerProtocol.Protocols.Student.PhoneNumber> phone
{
get { return _phone; }
}
[global::System.Serializable, global::ProtoBuf.ProtoContract(Name=@"PhoneNumber")]
public partial class PhoneNumber : global::ProtoBuf.IExtensible
{
public PhoneNumber() {}
private string _number;
[global::ProtoBuf.ProtoMember(1, IsRequired = true, Name=@"number", DataFormat = global::ProtoBuf.DataFormat.Default)]
public string number
{
get { return _number; }
set { _number = value; }
}
private ServerProtocol.Protocols.Student.PhoneType _type = ServerProtocol.Protocols.Student.PhoneType.Home;
[global::ProtoBuf.ProtoMember(2, IsRequired = false, Name=@"type", DataFormat = global::ProtoBuf.DataFormat.TwosComplement)]
[global::System.ComponentModel.DefaultValue(ServerProtocol.Protocols.Student.PhoneType.Home)]
public ServerProtocol.Protocols.Student.PhoneType type
{
get { return _type; }
set { _type = value; }
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
}
[global::ProtoBuf.ProtoContract(Name=@"PhoneType")]
public enum PhoneType
{
[global::ProtoBuf.ProtoEnum(Name=@"Mobile", Value=0)]
Mobile = 0,
[global::ProtoBuf.ProtoEnum(Name=@"Home", Value=1)]
Home = 1,
[global::ProtoBuf.ProtoEnum(Name=@"Work", Value=2)]
Work = 2
}
private global::ProtoBuf.IExtension extensionObject;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
{ return global::ProtoBuf.Extensible.GetExtensionObject(ref extensionObject, createIfMissing); }
}
}
编写类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProtoBuf;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace ServerProtocol
{
public class TestStudent
{
/// <summary>
/// 序列化对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="t"></param>
/// <returns></returns>
public byte[] SerializeStudent<T>(T t) where T:class
{
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize<T>(ms, t);
return ms.ToArray();
}
}
/// <summary>
/// 反序列化对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="arr"></param>
/// <returns></returns>
public T DeserializeStudent<T>(byte[] arr) where T : class
{
using (MemoryStream ms = new MemoryStream(arr))
{
return Serializer.Deserialize<T>(ms);
}
}
}
}
测试代码
static void Main(string[] args)
{
Student s = new Student();
s.name = "abc";
TestStudent test = new TestStudent();
byte[] arr = test.SerializeStudent<Student>(s);
Student st = test.DeserializeStudent<Student>(arr);
Console.WriteLine(st.name);
}
运行结果