下载:
开源项目地址如下:https://code.google.com/p/protobuf-net/
ProtoBuf-net可用于用于
(1)数据的存储(序列化和反序列化),类似于xml,json等;
(2)制作网络通信协议。
ProtoBuf-net序列化有两种方式:
1、直接使用开源项目提供的ProtoBuf-net r668\Full\unity\protobuf-net.dll,代码如下
namespace TestProtoBuf
{
[ProtoContract]
public class Address
{
[ProtoMember(1)]
public string Line1;
[ProtoMember(2)]
public string Line2;
}
[ProtoContract]
public class Person
{
[ProtoMember(1)]
public int Id;
[ProtoMember(2)]
public string Name;
[ProtoMember(3)]
public Address Addr;
}
class Program
{
static void Main(string[] args)
{
Person person = new Person();
person.Id = 1;
person.Name = "First";
person.Addr = new Address { Line1="line1", Line2="line2"};
// ProtoBuf序列化,这里使用数据存储功能
using(var file = System.IO.File.Create("Person.bin"))
{
ProtoBuf.Serializer.Serialize(file, person);
}
// ProtoBuf反序列化
Person binPerson = null;
using(var file = System.IO.File.OpenRead("Person.bin"))
{
binPerson = ProtoBuf.Serializer.Deserialize<Person>(file);
}
System.Console.WriteLine(binPerson.Name);
}
}
}
2、使用ProtoBuf提供的脚本来编写。脚本文件如***.proto,这种脚本格式简单、可读性强、方便扩展,用proto脚本定义网络协议是非常好用的。
下面是一个Proto脚本的简单例子:
message Person {
required string name=1;
required int32 id=2;
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;
}
requied是必须有的字段、optional是可有可无的字段、repeated是可以重复的字段(数组或列表),同时枚举字段都必须给出默认值。
接下来就可以使用ProgoGen来根据proto脚本生成源代码cs文件了,CMD运行命令行如下:
protogen -i:test.proto -0:test.cs -ns:MyProtoBuf
-i指定了输入,-o指定了输出,-ns指定了生成代码的namespace
运行后可以看到生成了一个C#文件,Unity导入该文件就可以使用定义的类了。
前边提到ProtoBuf-net可以用来存储数据(保存为.bin文件),也可以用来网络传输数据(主要为Byte[]),下边分别来介绍这两种写法:
1、存储数据
第一段代码已经给出了写法,只要用两个函数:
ProtoBuf.Serializer.Serialize(System.IO.Stream destination, T instance);
ProtoBuf.Serializer.Deserialize<T>(System.IO.Stream source);
2、网络传输
ProtoBuf没有序列化成Byte[]的方法,需要自己补充,类的定义如第一段代码对Person的定义,这里只给出Unity中测试序列化和反序列化的代码:
using UnityEngine;
using System.Collections;
using ProtoBuf;
using ProtoBuf.Meta;
public class TestProbuf_net : MonoBehaviour
{
// Use this for initialization
void Start () {
Person person = new Person
{
Id = 1,
Name = "First",
Address = new Address { Line1 = "Line1", Line2 = "Line2" }
};
//序列化
var arr = ProtobufSerialize(person);
//反序列化
var newPerson = ProtobufDeserialize<Person>(arr);
Debug.Log(newPerson.Name);
}
#region 序列化和反序列化的方法
/// <summary>
/// 使用protobuf把对象序列化为Byte数组
/// </summary>
/// <typeparam name="T">需要反序列化的对象类型,必须声明[ProtoContract]特征,且相应属性必须声明[ProtoMember(序号)]特征</typeparam>
/// <param name="obj"></param>
/// <returns></returns>
public static System.Byte[] ProtobufSerialize<T>(T obj)
{
using (var memory = new System.IO.MemoryStream())
{
Serializer.Serialize(memory, obj);
return memory.ToArray();
}
}
/// <summary>
/// 使用protobuf反序列化二进制数组为对象
/// </summary>
/// <typeparam name="T">需要反序列化的对象类型,必须声明[ProtoContract]特征,且相应属性必须声明[ProtoMember(序号)]特征</typeparam>
/// <param name="data"></param>
public static T ProtobufDeserialize<T>(System.Byte[] data) where T : class
{
using (var memory = new System.IO.MemoryStream(data))
{
return Serializer.Deserialize<T>(memory);
}
}
#endregion
}
附:
一些网上看到的,没尝试过,但可能以后会用到的东西:
1、protobuf-net.dll可能在ios中存在bug的问题
在Unity3D开发中,对于网络部分一般使用C#语言进行开发。一般推荐使用protobuf-net第三方库来进行开发。
但是不幸的是,其中使用到的JIT技术在Unity3D的IOS版本中是不能使用的,在序列化时会导致异常。
经过google网上搜索,找到一种不方便使用的解决方案如下:
但是该方案很复杂,非常不便于操作。
经过笔者自己的实验,探索出下面可用的一种解决方案:
1、从SVN上下载protbuf-net的源码:
http://protobuf-net.googlecode.com/svn/trunk/protobuf-net
2、将该目录中的所有C#源码拷贝到Unity3D中,直接使用源码而不是第三方dll;
3、此时在Unity中编译时,可能会报错说 unsafe不能使用;
4、采用如下方案可以解决: 在Assets目录下面新建 smcs.rsp文件,并在其中写入 -unsafe 字符串,前后不加空格;
5、重新启动unity,此时我们可以发现该工程能够通过编译;
经验证,该方案在IOS设备上也是可用的。从而保证我们的protobuf能够应用在Unity移动开发中。
2、序列化对象数组
List<Person> list = new List<Person>();
for (var i = 0; i < 1000; i++)
{
var person = new Person
{
Id = i,
Name = "Name"+i,List<Person> list = new List<Person>();
for (var i = 0; i < 1000; i++)
{
var person = new Person
{
Id = i,
Name = "Name"+i,
Address = new Address { Line1 = "Line1", Line2 = "Line2" }
};
list.Add(person);
}
using (var file = System.IO.File.Create("Person.bin"))
{
ProtoBuf.Serializer.Serialize(file, list);
}
Address = new Address { Line1 = "Line1", Line2 = "Line2" }
};
list.Add(person);
}
using (var file = System.IO.File.Create("Person.bin"))
{
ProtoBuf.Serializer.Serialize(file, list);
}