ProtoBuf-net

本文详细介绍了ProtoBuf-net的使用方法,包括数据存储与网络传输的应用场景。文章提供了序列化和反序列化的代码实例,以及如何在Unity环境中解决iOS平台上的兼容性问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下载:

开源项目地址如下: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网上搜索,找到一种不方便使用的解决方案如下:

http://www.frictionpointstudios.com/blog/2011/3/31/using-protobuf-net-serialization-in-unity-iphone.html

但是该方案很复杂,非常不便于操作。

经过笔者自己的实验,探索出下面可用的一种解决方案:

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);
            }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值