Unity使用protobuf

Google的Protobuf 本身是没有.net版本的。.net版的protobuf来源于proto社区,有两个版本:
一个版本叫protobuf-net,下载地址为:http://code.google.com/p/protobuf-net/  写法上比较符合c#一贯的写法,而且效率更高。
另一个为protobuf-csharp-sport , 官方站点:http://code.google.com/p/protobuf-csharp-port/ 写法上跟java上的使用极其相似,比较遵循Google 的原生态写法,跨平台选择此版本比较好。

protobuf-csharp-port

下面这个用法是参照protobuf-csharp-port的官方wiki,参见:

https://code.google.com/p/protobuf-csharp-port/wiki/GettingStarted

官方原文里的用法与代码已经有些不匹配了,需要做一些小的修改。

准备工作

1.首先从https://code.google.com/p/protobuf-csharp-port这个上面把源代码下载下来,我这个版本是protobuf-csharp-port-2.4.1.521-source(r523)

2.下载后是个压缩包,解压目录,如下图:

点开“Build”文件夹:

看见那个BuildAll.bat,点击它会自动执行编译操作,编译完成后将出现build_output和build_temp两个输出文件夹,其中build_output如下图所示例:

生成的Google.ProtocolBuffers.dll将被用作外部链接的DLL使用,这里有个问题,能不能不用做DLL使用呢?因为众所周知的AOT,JIT问题。

例子: an address book

这块将会用一个程序来演示如何使用这个protocBuffer

The .proto file

看看下面这个proto文件,分析下这个文件都描述了什么信息。此文件在 你下载的源代码文件夹的protos/tutorial。

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


这个文件和谷歌官方提供的基本一致,但做了一些调整:

  • 为了简单期间去掉了输出Java代码的选项。这里如果需要就把Java选项加上即可,和C#没有冲突。
  • 导入项代码: google/protobuf/csharp_options.proto ,目的是使用C#扩展。
  • 指定了两项C#特有的选项:
    • The name of the class containing the descriptor representing the overall .proto file. (This is called the "umbrella" class.) The generated source file is also named after this class. In this case we're using AddressBookProtos.
    • 生成类的命名空间。这里用的是: Google.ProtocolBuffers.Examples.AddressBook.
  • 指定了一个优化的选项。会多生成一些代码,但能提高运行效率。
  • 还有其他的选项,可以看看code.google上的description里的说明。

 

生成源代码

转到你的源代码目录,执行以下操作

protogen ..\..\protos\tutorial\addressbook.proto ..\..\protos\google\protobuf\csharp_options.proto ..\..\protos\google\protobuf\descriptor.proto --proto_path=..\..\protos

看看build_temp文件夹,如下图所示:

在GeneratedSource文件夹中,就能找到AddressBookProtos.cs文件了:

这个AddressBookProtos.cs文件是我们后边需要用到的,其他文件只是Google用到的,我们不用去管,或者能把这些代码作为源代码引入主工程?不得而知。

注意事项:

  1. Make sure that you do not use a non-ASCII encoding with your text file. The protoc.exe compiler will complain with the following message:
    tutorial/addressbook.proto:1:1: Expected top-level statement (e.g. "message").

    The best way to fix this is with Visual Studio. Open the proto file and select "File" -> "Save as...". From the save dialog click the down arrow next to     the save button and select "Save with Encoding". Select the "US-ASCII" codepage (near the bottom) and click save.

  2. It's often easiest keep all your proto files in a single directory tree. This allows to omit the --proto_path option by running protoc.exe from the top of     the this directory tree. Always keep the 'google/protobuf/*.proto' files available so that you can import them to specify options, or use the options     through protogen.

  3.Unlike a programming language like C# it is usually expected that your proto file will specify numerous messages, not one. Name your proto files     based on the namespace, not the message. Create proto files only as often as you would create a new namespace to organize those classes.

使用生成的源代码

为了使用上面生成的cs文件,我们需要执行下面这些操作:

  1. 创建一个builder,后边将用它来构造Person这个消息体
  2. 设置builder的属性
  3. 使用这个builder来创建 Person 消息体
  4. 将 Person 写入内存流
  5. 使用上面写好数据的内存流,再创建一个新的Person消息体
  6. 创建一个AddressBook的builder ,然后把这个刚创建的Person消息体赋值给它
  7. 使用AddressBook的builder 和上面的数据流创建 AddressBook

将这个AddressBook里的Person和第三步创建的Person进行比较,看数据是否一致。

static void Sample()
    {
        byte[] bytes;
        //Create a builder to start building a message
        Person.Builder newContact = Person.CreateBuilder();
        //Set the primitive properties
        newContact.SetId(1)
                  .SetName("Foo")
                  .SetEmail("foo@bar");
        //Now add an item to a list (repeating) field
        newContact.AddPhone(
            //Create the child message inline
            Person.Types.PhoneNumber.CreateBuilder().SetNumber("555-1212").Build()
            );
        //Now build the final message:
        Person person = newContact.Build();
        //The builder is no longer valid (at least not now, scheduled for 2.4):
        newContact = null;
        using(MemoryStream stream = new MemoryStream())
        {
            //Save the person to a stream
            person.WriteTo(stream);
            bytes = stream.ToArray();
        }
        //Create another builder, merge the byte[], and build the message:
        Person copy = Person.CreateBuilder().MergeFrom(bytes).Build();

        //A more streamlined approach might look like this:
        bytes = AddressBook.CreateBuilder().AddPerson(copy).Build().ToByteArray();
        //And read the address book back again
        AddressBook restored = AddressBook.CreateBuilder().MergeFrom(bytes).Build();
        //The message performs a deep-comparison on equality:
        if(restored.PersonCount != 1 || !person.Equals(restored.PersonList[0]))
            throw new ApplicationException("There is a bad person in here!");
    }


   用VS2013,创建一个WinForm程序,拖一个button上去,双击出事件,调用Sample函数即可,这样就通了。里面还有很多细节没说清楚,不过好歹有整块的东西了。那么后边的工作,需要分成几步来执行:

1.将上述流程分析清楚,有一个初步的架构图和UML图。

2.C#客户端的二进制内存流,显示需要铺设一个二进制的内存流管理器,是否需要参考之前的那个二进制管理器呢。

3.如何集成到Unity里,首先要写一份关于Unity的代码规范和内存处理规范。如果集成到Unity里,那么势必两头都要写代码,加油啊。

4.如何搭建一个Java服务器,支持解析数据,并发送和接收。

5.连接Java服务器通信。客户端和服务器两头看看能否顺利工作。


protobuf-net

这里使用的是protobuf-net,下载解压后,将Precompile\precompile.exe 以及 ProtoGen\protogen.exe 两个文件加入到环境变量中,打开cmd,使用方法如下:

protogen -i:input.proto -o:output.cs  
protogen -i:input.proto -o:output.xml -t:xml  
protogen -i:input.proto -o:output.cs -p:datacontract -q  
protogen -i:input.proto -o:output.cs -p:observable=true 
以E:\proto\myproto.proto为例,cmd下输入
protogen -i:e:\proto\myproto.proto -o:myproto.cs 

运行成功后就会在文件夹内生成myproto.cs文件

如何将myproto.cs加入你的项目中
有两种方法可以将.cs文件加入到你的项目中:第一种就是预编译成.dll文件,然后加入到你的项目中就可以了。第二种就是直接使用源码(这样的话编译速度会比较慢),将你的.cs文件直接加入到你的项目中,然后在项目中引用protobuf-net.dll的库,就可以使用了。

官方写法:

Install

Nuget : Install-Package protobuf-net

基本用法

1 修改你的类

[ProtoContract]
class Person {
    [ProtoMember(1)]
    public int Id {get;set;}
    [ProtoMember(2)]
    public string Name {get;set;}
    [ProtoMember(3)]
    public Address Address {get;set;}
}
[ProtoContract]
class Address {
    [ProtoMember(1)]
    public string Line1 {get;set;}
    [ProtoMember(2)]
    public string Line2 {get;set;}
}

Note that unlike XmlSerializer, the member-names are not encoded in the data - instead, you must pick an integer to identify each member. Additionally, to show intent it is necessary to show that we intend this type to be serialized (i.e. that it is a data contract).

2 序列化你的数据

This writes a 32 byte file to "person.bin" :

var person = new Person {
    Id = 12345, Name = "Fred",
    Address = new Address {
        Line1 = "Flat 1",
        Line2 = "The Meadows"
    }
};
using (var file = File.Create("person.bin")) {
    Serializer.Serialize(file, person);
}

3 反序列化数据

This reads the data back from "person.bin" :

Person newPerson;
using (var file = File.OpenRead("person.bin")) {
    newPerson = Serializer.Deserialize<Person>(file);
}

参考文章:
在ios android设备上使用 Protobuf (使用源码方式)    http://game.ceeger.com/forum/read.php? tid=14359&fid=27&page=1
android与PC,C#与Java利用protobuf 进行无障碍通讯 http://www.cnblogs.com/TerryBlog/archive/2011/04/23/2025654.html
windows下Google Protocol Buffer 编译安装教程 http://kuaile.in/archives/1214

参考1:http://www.cnblogs.com/designyourdream/p/4267230.html

参考2:http://blog.csdn.net/flywarrior/article/details/47359749#

Unity使用Protobuf需要按照Protobuf的语法规范,先定义好Proto文件,然后使用Protobuf官方工具将Proto文件转换成C#文件,再将该C#文件和Protobuf库文件导入到Unity中。\[1\] 在Unity使用Protobuf,首先需要下载Protobuf包,并在Proto目录下创建一个Proto文件,例如Request.Proto。在该Proto文件中,按照Protobuf的语法规范定义消息类型和字段。例如,可以定义一个名为RequestMsg的消息类型,包含name、len和buff字段。其中,buff字段是一个数组,相当于C#的List。\[2\] 需要注意的是,Protobuf会压缩无用的空间,所以在使用网络调试助手查看数据时可能不太直观。但可以通过查看生成的.cs文件中对应类型的赋值解析方式来理解数据的结构。例如,可以查看生成的.cs文件中对应的WriteTo方法,其中会显示每个字段对应的Tag和值。\[3\] 总结来说,Unity使用Protobuf需要定义Proto文件,将其转换成C#文件,并导入到Unity使用。在使用网络调试助手查看数据时,可以通过查看生成的.cs文件中的赋值解析方式来理解数据的结构。 #### 引用[.reference_title] - *1* *2* [Unity如何使用Protobuf](https://blog.csdn.net/foupwang/article/details/104732951)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Unity使用Protobuf](https://blog.csdn.net/weixin_39196123/article/details/126617113)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值