Unity3D客户端和Java服务端使用Protobuf

合集下载

Unity3D游戏GC优化总结---protobuf-net无GC版本优化实践

Unity3D游戏GC优化总结---protobuf-net无GC版本优化实践

Unity3D游戏GC优化总结---protobuf-net⽆GC版本优化实践⼀ protobuf-net优化效果图 protobuf-net是Unity3D游戏开发中被⼴泛使⽤的Google Protocol Buffer库的c#版本,之所以c#版本被⼴泛使⽤,是因为c++版本的源代码不⽀持Unity3D游戏在各个平台上的动态库构建。

它是⼀个⽹络传输层协议,对应的lua版本有两个可⽤的库:⼀个是proto-gen-lua,由tolua作者开发,另外⼀个是protoc,由云风开发。

protobuf-net在GC上有很⼤的问题,在⼀个⾼频率⽹络通讯的状态同步游戏中使⽤发现GC过⾼,所以对它进⾏了⼀次⽐较彻底的GC优化。

下⾯是优化前后的对⽐图:protobuf-net优化前GC和性能效果图protobuf-net优化后GC和性能效果图⼆ Unity3D游戏GC优化概述 有关Unity3D垃圾回收的基本概念和优化策略Unity官⽹有发布过⽂章:。

这篇⽂章讲述了Unity3D垃圾回收机制,和⼀些简单的优化策略,讨论的不是特别深⼊,但是⼴度基本上算是够了。

我罗列⼀下这篇⽂章的⼀些要点,如果你对其中的⼀些点不太熟悉,建议仔细阅读下这篇⽂章: 1、C#变量分为两种类型:值类型和引⽤类型,值类型分配在栈区,引⽤类型分配在堆区,GC关注引⽤类型 2、GC卡顿原因:堆内存垃圾回收,向系统申请新的堆内存 3、GC触发条件:堆内存分配⽽当内存不⾜时、按频率⾃动触发、⼿动强⾏触发(⼀般⽤在场景切换) 4、GC负⾯效果:内存碎⽚(导致内存变⼤,GC触发更加频繁)、游戏顿卡 5、GC优化⽅向:减少GC次数、降低单次GC运⾏时间、场景切换时主动GC 6、GC优化策略:减少对内存分配次数和引⽤次数、降低堆内存分配和回收频率 7、善⽤缓存:对有堆内存分配的函数,缓存其调⽤结果,不要反复去调⽤ 8、清除列表:⽽不要每次都去new⼀个新的列表 9、⽤对象池:必⽤ 10、慎⽤串拼接:缓存、Text组件拆分、使⽤StringBuild、Debug.Log接⼝封装(打Conditional标签) 11、警惕Unity函数调⽤:、GameObject.tag、FindObjectsOfType<T>()等众多函数都有堆内存分配,实测为准 12、避免装箱:慎⽤object形参、多⽤泛型版本(如List<T>)等,这⾥的细节问题很多,实测为准 13、警惕协程:StartCoroutine有GC、yield return带返回值有GC、yield return new xxx有GC(最好⾃⼰做⼀套协程管理) 14、foreach:unity5.5之前版本有GC,使⽤for循环或者获取迭代器 15、减少引⽤:建⽴管理类统⼀管理,使⽤ID作为访问token 16、慎⽤LINQ:这东西最好不⽤,GC很⾼ 17、结构体数组:如果结构体中含有引⽤类型变量,对结构体数组进⾏拆分,避免GC时遍历所有结构体成员 18、在游戏空闲(如场景切换时)强制执⾏GC三 protobuf-net GC分析3.1 protobuf-net序列化 先分析下序列化GC,deep profile如下: 打开PropertyDecorator.cs脚本,找到Write函数如下:1public override void Write(object value, ProtoWriter dest)2 {3 Helpers.DebugAssert(value != null);4 value = property.GetValue(value, null);5if(value != null) Tail.Write(value, dest);6 }View Code 可以看到这⾥MonoProperty.GetValue产⽣GC的原因是因为反射的使⽤;⽽ListDecorator.Write对应于代码Tail.Write,继续往下看: 找到对应源代码:1public override void Write(object value, ProtoWriter dest)2 {3 SubItemToken token;4bool writePacked = WritePacked;5if (writePacked)6 {7 ProtoWriter.WriteFieldHeader(fieldNumber, WireType.String, dest);8 token = ProtoWriter.StartSubItem(value, dest);9 ProtoWriter.SetPackedField(fieldNumber, dest);10 }11else12 {13 token = new SubItemToken(); // default14 }15bool checkForNull = !SupportNull;16foreach (object subItem in (IEnumerable)value)17 {18if (checkForNull && subItem == null) { throw new NullReferenceException(); }19 Tail.Write(subItem, dest);20 }21if (writePacked)22 {23 ProtoWriter.EndSubItem(token, dest);24 }25 }View Code 可以看到这⾥的GC是由list遍历的foreach引起的。

PROTOBUF使用例子

PROTOBUF使用例子
if (server != null) { try { server.close(); } catch (IOException e) { e.printStackTrace(); }
} if (socket != null) {
try { socket.close();
} catch (IOException e) { e.printStackTrace();
// 通过 toByteArray 方法序列化成二进制数据
byte[] bytes = builder.build().toByteArray();
int length = bytes.length;
ous.write(length); ous.write(bytes); ous.flush();
System.out.println("length=" + length);
private final static int PORT = 8080;
public static void main(String[] args) { ServerSocket server = null; InputStream ins = null; OutputStream ous = null; Socket socket = null; try { server = new ServerSocket(PORT);
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ins != null) {

使用protobuf进行C#与Java通信

使用protobuf进行C#与Java通信

使用protobuf进行C#与Java通信在之前已写一篇关于ProtoBuf的文章了,主要是.net版本的实现。

今天主要是讲如何利用ProtoBuf定义一个协议,来实现C#与Java双方进行通信(这个通信指的是双方数据协议,而不是通信协议。

)ProtoBuf 应用场景个人认为,主要用于数据交互和共享,此种情况需要双方制定一个特定的数据结构。

那么使用ProtoBuf 定义一个数据结构,然后大家从这个描述文件,各自生成自己使用的编程语言对应的代码文件,再使用这些代码对双方的数据进行处理。

那么,只要都遵守这个数据文件格式,数据共享就可以实现夸平台。

如果数据描述文件做了修改,只要遵守一定的规则,那么原有数据还是可以兼容使用的。

这个就是做了一个平台无关的文件与平台和语言相关的数据对象之间的适配转化工作,就和很多xml解析器一样。

实现C#与Java通信步骤1.定义协议创建一个以.proto为后缀的文件,本篇创建了一个名为msg.proto的消息文件,具体信息如下:package tutorial;option java_package = "com.protobuftest.protobuf"; (生成Java类时包名;C#类的命名空间)option java_outer_classname = "PersonProbuf"; (生成Java、C#类的类名)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;message CountryInfo {required string name = 1;required string code = 2;optional int32 number = 3;}}message AddressBook {repeated Person person = 1;}package在Java里面代表这个文件所在的包名,在c#里面代表该文件的命名空间;message代表一个类;required 代表该字段必填;optional 代表该字段可选,并可以为其设置默认值,默认值格式:[defalut=Home],它是一个枚举类型。

protobuf用法

protobuf用法

protobuf用法Protobuf 是一种高效且可扩展的序列化数据格式,可以用于在不同平台和语言之间进行数据交换。

使用 protobuf 的一般步骤如下:1. 定义数据结构:使用 `.proto` 文件来定义数据结构。

这些文件使用 Protobuf 的语法来描述数据的字段、类型和其它属性。

2. 编译 `.proto` 文件:使用 protobuf 编译器将 `.proto` 文件编译成目标语言的代码。

编译器会根据目标语言生成相应的类和方法,用于序列化和反序列化数据。

3. 序列化数据:在发送方,将数据对象(即定义的数据结构生成的类的实例)序列化为字节流。

这样的字节流可以在网络上传输或存储到文件中。

4. 反序列化数据:在接收方,将收到的字节流反序列化为数据对象,以便对数据进行进一步处理。

下面是一个示例的 `.proto` 文件:```syntax = "proto3";message Person {string name = 1;int32 age = 2;repeated string hobbies = 3;}```通过以上定义的 `.proto` 文件,我们可以使用 protobuf 编译器生成对应的代码。

例如,在 Java 中可以使用 `protoc` 命令行工具来编译 `.proto` 文件:```protoc -I=./ --java_out=./ path/to/your.proto```这将会在当前目录下生成名为 `your.proto` 的 Java 类。

之后,你可以在 Java 代码中使用生成的类来创建、序列化和反序列化数据对象。

比如:```javaPerson.Builder personBuilder = Person.newBuilder(); personBuilder.setName("John");personBuilder.setAge(25);personBuilder.addHobbies("reading");personBuilder.addHobbies("hiking");Person person = personBuilder.build();byte[] serializedData = person.toByteArray();```在这个示例中,首先创建了一个 `Person.Builder` 的实例,然后通过 builder 来设置对象的各个属性。

C#使用ProtocolBuffer(ProtoBuf)进行Unity中的Socket通信

C#使用ProtocolBuffer(ProtoBuf)进行Unity中的Socket通信

C#使⽤ProtocolBuffer(ProtoBuf)进⾏Unity中的Socket通信⾸先来说⼀下本⽂中例⼦所要实现的功能:基于ProtoBuf序列化对象使⽤Socket实现时时通信数据包的编码和解码下⾯来看具体的步骤:⼀、Unity中使⽤ProtoBuf导⼊DLL到Unity中,创建⽹络传输的模型类:using System;using ProtoBuf;//添加特性,表⽰可以被ProtoBuf⼯具序列化[ProtoContract]public class NetModel {//添加特性,表⽰该字段可以被序列化,1可以理解为下标[ProtoMember(1)]public int ID;[ProtoMember(2)]public string Commit;[ProtoMember(3)]public string Message;}using System;using ProtoBuf;//添加特性,表⽰可以被ProtoBuf⼯具序列化[ProtoContract]public class NetModel {//添加特性,表⽰该字段可以被序列化,1可以理解为下标[ProtoMember(1)]public int ID;[ProtoMember(2)]public string Commit;[ProtoMember(3)]public string Message;}在Unity中添加测试脚本,介绍ProtoBuf⼯具的使⽤。

using System;using System.IO;public class Test : MonoBehaviour {void Start () {//创建对象NetModel item = new NetModel(){ID = 1, Commit = "LanOu", Message = "Unity"};//序列化对象byte[] temp = Serialize(item);//ProtoBuf的优势⼀:⼩Debug.Log(temp.Length);//反序列化为对象NetModel result = DeSerialize(temp);Debug.Log(result.Message);}// 将消息序列化为⼆进制的⽅法// < param name="model">要序列化的对象< /param>private byte[] Serialize(NetModel model){try {//涉及格式转换,需要⽤到流,将⼆进制序列化到流中using (MemoryStream ms = new MemoryStream()) {//使⽤ProtoBuf⼯具的序列化⽅法ProtoBuf.Serializer.Serialize<NetModel> (ms, model);//定义⼆级制数组,保存序列化后的结果byte[] result = new byte[ms.Length];//将流的位置设为0,起始点ms.Position = 0;//将流中的内容读取到⼆进制数组中ms.Read (result, 0, result.Length);return result;}} catch (Exception ex) {Debug.Log ("序列化失败: " + ex.ToString());return null;}}// 将收到的消息反序列化成对象// < returns>The serialize.< /returns>// < param name="msg">收到的消息.</param>private NetModel DeSerialize(byte[] msg){try {using (MemoryStream ms = new MemoryStream()) {//将消息写⼊流中ms.Write (msg, 0, msg.Length);//将流的位置归0ms.Position = 0;//使⽤⼯具反序列化对象NetModel result = ProtoBuf.Serializer.Deserialize<NetModel> (ms);return result;}} catch (Exception ex) {Debug.Log("反序列化失败: " + ex.ToString());return null;}}}using System;using System.IO;public class Test : MonoBehaviour {void Start () {//创建对象NetModel item = new NetModel(){ID = 1, Commit = "LanOu", Message = "Unity"}; //序列化对象byte[] temp = Serialize(item);//ProtoBuf的优势⼀:⼩Debug.Log(temp.Length);//反序列化为对象NetModel result = DeSerialize(temp);Debug.Log(result.Message);}// 将消息序列化为⼆进制的⽅法// < param name="model">要序列化的对象< /param>private byte[] Serialize(NetModel model){try {//涉及格式转换,需要⽤到流,将⼆进制序列化到流中using (MemoryStream ms = new MemoryStream()) {//使⽤ProtoBuf⼯具的序列化⽅法ProtoBuf.Serializer.Serialize<NetModel> (ms, model);//定义⼆级制数组,保存序列化后的结果byte[] result = new byte[ms.Length];//将流的位置设为0,起始点ms.Position = 0;//将流中的内容读取到⼆进制数组中ms.Read (result, 0, result.Length);return result;}} catch (Exception ex) {Debug.Log ("序列化失败: " + ex.ToString());return null;}}// 将收到的消息反序列化成对象// < returns>The serialize.< /returns>// < param name="msg">收到的消息.</param>private NetModel DeSerialize(byte[] msg){try {using (MemoryStream ms = new MemoryStream()) {//将消息写⼊流中ms.Write (msg, 0, msg.Length);//将流的位置归0ms.Position = 0;//使⽤⼯具反序列化对象NetModel result = ProtoBuf.Serializer.Deserialize<NetModel> (ms); return result;}} catch (Exception ex) {Debug.Log("反序列化失败: " + ex.ToString());return null;}}}⼆、Unity中使⽤Socket实现时时通信通信应该实现的功能:服务器可以时时监听多个客户端服务器可以时时监听某⼀个客户端消息服务器可以时时给某⼀个客户端发消息⾸先我们需要定义⼀个客户端对象using System;using .Sockets;// 表⽰⼀个客户端public class NetUserToken {//连接客户端的Socketpublic Socket socket;//⽤于存放接收数据public byte[] buffer;public NetUserToken(){buffer = new byte[1024];}// 接受消息// < param name="data">Data.< /param>public void Receive(byte[] data){UnityEngine.Debug.Log("接收到消息!");}// 发送消息//< param name="data">Data.< /param>public void Send(byte[] data){}}using System;using .Sockets;// 表⽰⼀个客户端public class NetUserToken {//连接客户端的Socketpublic Socket socket;//⽤于存放接收数据public byte[] buffer;public NetUserToken(){buffer = new byte[1024];}// 接受消息// < param name="data">Data.< /param>public void Receive(byte[] data){UnityEngine.Debug.Log("接收到消息!");}// 发送消息//< param name="data">Data.< /param>public void Send(byte[] data){}}然后实现我们的服务器代码using System.Collections;using System.Collections.Generic;using ;using System;using .Sockets;public class NetServer{//单例脚本public static readonly NetServer Instance = new NetServer();//定义tcp服务器private Socket server;private int maxClient = 10;//定义端⼝private int port = 35353;//⽤户池private Stack<NetUserToken> pools;private NetServer(){//初始化socketserver = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);server.Bind(new IPEndPoint(IPAddress.Any, port));}//开启服务器public void Start(){server.Listen(maxClient);UnityEngine.Debug.Log("Server OK!");//实例化客户端的⽤户池pools = new Stack<NetUserToken>(maxClient);for(int i = 0; i < maxClient; i++){NetUserToken usertoken = new NetUserToken();pools.Push(usertoken);}//可以异步接受客户端, BeginAccept函数的第⼀个参数是回调函数,当有客户端连接的时候⾃动调⽤ server.BeginAccept (AsyncAccept, null);}//回调函数,有客户端连接的时候会⾃动调⽤此⽅法private void AsyncAccept(IAsyncResult result){try {//结束监听,同时获取到客户端Socket client = server.EndAccept(result);UnityEngine.Debug.Log("有客户端连接");//来了⼀个客户端NetUserToken userToken = pools.Pop();userToken.socket = client;//客户端连接之后,可以接受客户端消息BeginReceive(userToken);//尾递归,再次监听是否还有其他客户端连⼊server.BeginAccept(AsyncAccept, null);} catch (Exception ex) {UnityEngine.Debug.Log(ex.ToString());}}//异步监听消息private void BeginReceive(NetUserToken userToken){try {//异步⽅法userToken.socket.BeginReceive(userToken.buffer, 0, userToken.buffer.Length, SocketFlags.None, EndReceive, userToken);} catch (Exception ex) {UnityEngine.Debug.Log(ex.ToString());}}//监听到消息之后调⽤的函数private void EndReceive(IAsyncResult result){try {//取出客户端NetUserToken userToken = result.AsyncState as NetUserToken;//获取消息的长度int len = userToken.socket.EndReceive(result);if(len > 0){byte[] data = new byte[len];Buffer.BlockCopy(userToken.buffer, 0, data, 0, len);//⽤户接受消息userToken.Receive(data);//尾递归,再次监听客户端消息BeginReceive(userToken);}} catch (Exception ex) {UnityEngine.Debug.Log(ex.ToString());}}}using System.Collections;using System.Collections.Generic;using ;using System;using .Sockets;public class NetServer{//单例脚本public static readonly NetServer Instance = new NetServer();//定义tcp服务器private Socket server;private int maxClient = 10;//定义端⼝private int port = 35353;//⽤户池private Stack<NetUserToken> pools;private NetServer(){//初始化socketserver = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);server.Bind(new IPEndPoint(IPAddress.Any, port));}//开启服务器public void Start(){server.Listen(maxClient);UnityEngine.Debug.Log("Server OK!");//实例化客户端的⽤户池pools = new Stack<NetUserToken>(maxClient);for(int i = 0; i < maxClient; i++){NetUserToken usertoken = new NetUserToken();pools.Push(usertoken);}//可以异步接受客户端, BeginAccept函数的第⼀个参数是回调函数,当有客户端连接的时候⾃动调⽤server.BeginAccept (AsyncAccept, null);}//回调函数,有客户端连接的时候会⾃动调⽤此⽅法private void AsyncAccept(IAsyncResult result){try {//结束监听,同时获取到客户端Socket client = server.EndAccept(result);UnityEngine.Debug.Log("有客户端连接");//来了⼀个客户端NetUserToken userToken = pools.Pop();userToken.socket = client;//客户端连接之后,可以接受客户端消息BeginReceive(userToken);//尾递归,再次监听是否还有其他客户端连⼊server.BeginAccept(AsyncAccept, null);} catch (Exception ex) {UnityEngine.Debug.Log(ex.ToString());}}//异步监听消息private void BeginReceive(NetUserToken userToken){try {//异步⽅法userToken.socket.BeginReceive(userToken.buffer, 0, userToken.buffer.Length, SocketFlags.None,EndReceive, userToken);} catch (Exception ex) {UnityEngine.Debug.Log(ex.ToString());}}//监听到消息之后调⽤的函数private void EndReceive(IAsyncResult result){try {//取出客户端NetUserToken userToken = result.AsyncState as NetUserToken;//获取消息的长度int len = userToken.socket.EndReceive(result);if(len > 0){byte[] data = new byte[len];Buffer.BlockCopy(userToken.buffer, 0, data, 0, len);//⽤户接受消息userToken.Receive(data);//尾递归,再次监听客户端消息BeginReceive(userToken);}} catch (Exception ex) {UnityEngine.Debug.Log(ex.ToString());}}}在Unity中开启服务器,并使⽤C#控制台模拟客户端连接、发送消息操作。

protobuf生成java 命令参数

protobuf生成java 命令参数

protobuf生成java 命令参数摘要:1.简介2.protobuf 文件概述3.protobuf 生成Java 代码的命令参数4.使用示例5.总结正文:1.简介Protocol Buffers(简称protobuf)是一种轻便高效的结构化数据存储格式,可以用于序列化结构化数据。

它非常适合用于数据存储、通信协议等方面。

在使用protobuf 时,需要使用protoc 编译器将.proto 文件编译为目标语言(如Java)的源代码。

本文将介绍使用protobuf 生成Java 代码的命令参数。

2.protobuf 文件概述在开始使用protobuf 之前,需要先创建一个.proto 文件。

.proto 文件包含了一组用于描述数据结构的语句。

例如:```syntax = "proto3";message Person {string name = 1;int32 age = 2;string email = 3;}```这个例子定义了一个名为"Person"的消息,包含三个字段:name、age 和email。

3.protobuf 生成Java 代码的命令参数要生成Java 代码,需要使用protoc 编译器。

以下是生成Java 代码的常用命令参数:- `protoc`:编译器命令。

- `-I`:指定.proto 文件的搜索路径。

- `--java_out`:指定生成Java 代码的输出路径。

- `--plugin`:指定使用的protobuf 插件,例如:`protoc-gen-grpc-java=path/to/grpc-java-plugin`。

一个完整的示例命令如下:```protoc -I.--java_out=./java_output --plugin=protoc-gen-grpc-java=path/to/grpc-java-plugin Person.proto```这个命令将生成一个名为"Person.java"的文件,其中包含了对"Person"消息结构的序列化和反序列化方法。

在Java中使用protobuf序列化对象

在Java中使用protobuf序列化对象

在Java中使⽤protobuf序列化对象什么是protobuf它是⼀个对象序列化/反序列化的⼯具,什么是对象的序列化/反序列化?就是把⼀个Java堆中存活的对象转换成⼀串⼆进制编码,然后该编码可以⽤于本地存储和⽹络传输。

反序列化就是根据⼀串⼆进制编码还原出原来的那个对象,protobuf能够将⼀个对象以特定的格式转换为⼀个⼆进制串(序列化),然后将⼆进制串还原成对象(反序列化)。

这⾥涉及到两个指标:对同⼀个⽬标对象:1)序列化和反序列化的时间开销,2)序列化之后串的长度protobuf在这两个⽅⾯都有⾮常出⾊的表现(⽹传)在Windows下使⽤protobuf的步骤如下:第⼀步:下载protoc-2.5.0-win32.zip,得到其中的protoc.exe.然后将该protoc.exe的存放路径加⼊Path环境变量,便于访问。

⽐如,我的protoc.exe存放于D:/protobuf,环境变量中添加如下配置:D:/protobuf第⼆步:编写.proto⽂件,它是序列化⼀个对象的“模板”,protobuf就是根据它来决定如何序列化和反序列化。

编写的person-entity.proto配置⽂件如下:option java_outer_classname = "PersonEntity";//⽣成的数据访问类的类名message Person {required int32 id = 1;//同上required string name = 2;//必须字段,在后⾯的使⽤中必须为该段设置值optional string email = 3;//可选字段,在后⾯的使⽤中可以⾃由决定是否为该字段设置值}message字段代表了⼀个对象,所以,可以使⽤message实现对象的嵌套序列化required表⽰是强制字段,在后⾯的使⽤中必须为该字段设置值;optional表⽰是可选字段,在后⾯的使⽤中可选地为该字段设置值;repeated表⽰集合类型,可以填充多个数据后⾯的1,2,3是字段的编号,字段名是让⽤户使⽤的,字段编号则是让系统识别的,从1开始。

protobuf 使用场景

protobuf 使用场景

protobuf 使用场景(原创版)目录1.Protocol Buffers 简介2.Protobuf 的使用场景3.场景一:数据存储和交换4.场景二:网络通信5.场景三:序列化和反序列化6.场景四:跨平台和跨语言7.结论正文1.Protocol Buffers 简介Protocol Buffers(简称 protobuf)是一种轻便高效的结构化数据存储格式,可以用于序列化结构化数据。

它比 XML 和 JSON 更小、更快,易于解析和生成。

protobuf 是由 Google 开发的一种数据交换格式,可以用于各种场景,如数据存储、网络通信等。

2.Protobuf 的使用场景protobuf 具有广泛的应用场景,下面将分别介绍四个主要的应用场景。

3.场景一:数据存储和交换protobuf 可以被用于存储和交换结构化数据。

由于其紧凑的二进制格式,protobuf 比 XML 和 JSON 更适合用于存储大量数据。

此外,protobuf 具有易于解析和生成的特点,可以简化数据处理的过程。

因此,protobuf 在需要存储和交换结构化数据的场景中具有很大的优势。

4.场景二:网络通信protobuf 在网络通信领域也有广泛的应用。

由于其紧凑的二进制格式和易于解析的特点,protobuf 可以有效地减少网络传输的带宽消耗和延迟。

此外,protobuf 支持跨平台和跨语言,可以在各种操作系统和编程语言之间进行数据交换。

因此,protobuf 在需要进行网络通信的场景中具有很大的优势。

5.场景三:序列化和反序列化protobuf 可以对结构化数据进行序列化和反序列化。

序列化是将数据结构转换为二进制格式,以便于存储和传输;反序列化是将二进制数据转换回原始数据结构。

由于其紧凑的二进制格式和易于解析的特点,protobuf 在序列化和反序列化方面具有很高的性能。

因此,protobuf 在需要对结构化数据进行序列化和反序列化的场景中具有很大的优势。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Unity3D客户端和Java服务端使用Protobuf本文测试环境:系统:WINDOWS 7(第3、6步)、OS X 10.9(第4步)软件:VS 2012(第3、6步)、Eclipse(第5、6步)硬件:iPad 2(第4步)、Macbook Pro Mid 2012(第4步)文章目录:1、关于Protobuf的C#实现2、为什么有些Protobuf发布到iOS就用不了,甚至有些在PC都用不了?3、手动处理C#版本的Protobuf3.1、创建一个C#工程,先手动创建每一个要通过Protobuf序列化或反序列化的数据模型类,然后导出dll3.2、创建一个用于序列化的C#工程,然后运行生成dll3.3、将上面两个工程生成的dll拖到unity中4、在Unity中反序列化Protobuf5、服务端Java也用Protobuf6、太烦了?!客户端也要自动处理Protobuf1、关于Protobuf 的C#实现首先,U3D里面Protobuf使用的是C#的实现,那么目前有几个可选的C#实现:C#: /p/protobuf-csharp-portC#: /p/protosharp/C#: https:///protobuf/C#/.NET/WCF/VB: /p/protobuf-net/我这里选用的是/p/protobuf-net/(你可以在https:///p/protobuf-net/downloads/list 这里下载到他的代码和工具),它比较好的一点是,提供了各种平台的支持,解压后在“Full”目录中可以看到各个平台的支持看到里面的unity了吗,它里面的protobuf-net.dll将是我们准备用到的。

2、为什么有些Protobuf发布到iOS就用不了,甚至有些在PC都用不了?a、Protobuf使用了JIT,即在运行时动态编译,而这个特性在Unity发布到iOS时候是不支持的。

因此,会导致你在PC 上可以正常运行,发布到iOS就有问题。

b、Protobuf是基于.net 2.0以上框架写的,而Unity仅支持.net 2.0,或者有些使用2.0中比较多的特性,而你在Unity 中发布设置了.net 2.0的子集。

后者你只需要在Player setting中修改设置就可以了。

上面两项也可适用于其它第三方类库,如果你自己下载了一个在PC上或C#里面能正常使用的类库,在U3D里面就不能用了,那么请检查是否是上面两条原因导致的。

3、手动处理C#版本的Protobuf知道了上面问题,我们只要选一个.net2.0的Protobuf,然后它又不是JIT,那就可以正常使用了。

这里用的思路是:3.1、创建一个C#工程,先手动创建每一个要通过Protobuf序列化或反序列化的数据模型类,然后导出dll 以VS为例,首先,创建一个类库工程:“文件”&gt;"新建"&gt;"项目"&gt;"类库"(记得选择 .net framework 2.0)将unity的protobuf的dll添加到项目引用然后假设你有一个类WorkerInfo是需要通过Protobuf进行序列化和反序列化的,那么创建一个WorkerInfo类,内容如下:[csharp] view plaincopyprint?using System;using System.Collections.Generic;using System.Text;using ProtoBuf;namespace Com.YourCompany.Project.Proto.Module{ [ProtoContract]public class WorkerInfo {[ProtoMember(1)]public int workerId;[ProtoMember(2)]public int leftClosingTimeSec;[ProtoMember(3)]public int buildingId;}} using System;using System.Collections.Generic;using System.Text;using ProtoBuf;namespace Com.YourCompany.Project.Proto.Module{ [ProtoContract]public class WorkerInfo { [ProtoMember(1)] public int workerId; [ProtoMember(2)]public int leftClosingTimeSec;[ProtoMember(3)]public int buildingId; }}按下Shift+F6生成dll,在项目的bin\Debug目录下就可以找到ProtoModelDLL.dll了 3.2、创建一个用于序列化的C#工程,然后运行生成dll也是以VS为例,首先创建一个控制台应用程序:“文件”&gt;"新建"&gt;"项目"&gt;"控制台应用程序"(记得选择 .net framework 2.0)将Protobuf和3.1生成的dll添加到引用在项目生成的Program.cs中写入:[csharp] view plaincopyprint?using System;using System.Collections.Generic;using System.Text;using ProtoBuf.Meta;using ProtoBuf;using piler;using Com.YourCompany.Project.Proto.Module;namespace ProtoModelSerializerCreator{class Program{static void Main(string[] args){var model = TypeModel.Create();model.Add(typeof(object), true);model.Add(typeof(WorkerInfo), true);model.AllowParseableTypes = true;model.AutoAddMissingTypes = true;pile("ProtoModelSerializer", "ProtoModelSerializer.dll");}}} using System;using System.Collections.Generic;using System.Text;using ProtoBuf.Meta;using ProtoBuf;using piler;usingCom.YourCompany.Project.Proto.Module;namespace ProtoModelSerializerCreator{class Program{static void Main(string[] args){var model = TypeModel.Create();model.Add(typeof(object), true);model.Add(typeof(WorkerInfo), true); model.AllowParseableTypes = true;model.AutoAddMissingTypes = true;pile("ProtoModelSerializer", "ProtoModelSerializer.dll");}}}然后ctrl+F5运行,这时候你就可以在bin\Debug中看到ProtoModelSerializer.dll。

3.3、将上面两个工程生成的dll(ProtoModelDLL.dll和ProtoModelSerializer.dll)以及protobuf-net.dll拖到unity中怎么用?看第4步4、在Unity中反序列化Protobuf由于一般游戏客户端请求的数据量比较简单,也比较少,因此我们前端请求是不直接二进制请求。

而前端收到后端返回才采用了Protobuf,因此。

这里讨论Protobuf的反序列化。

代码很简单,下面写个测试代码:[csharp] view plaincopyprint?using UnityEngine;using System.Collections;using ProtoBuf.Meta;using Com.YourCompany.Project.Proto.Module;using System.IO;using Com.Duoyu001.Proto.Building;using Com.Duoyu001.Proto.Worker;public class TestProto : MonoBehaviour{// initvoid Start (){byte[] dataFromServ = new byte[]{8, 233, 7, 16, 100, 24, 1}; //these bytes are generated by serverRuntimeTypeModel serializer = BitchSerializer.Create ();System.IO.MemoryStream memStream = new System.IO.MemoryStream ();WorkerInfo w = new WorkerInfo ();serializer.Deserialize (memStream, w, w.GetType ()); //asign value to proto modelDebug.Log (w.workerId + ", " + w.buildingId + ", " + w.leftClosingTimeSec);}} using UnityEngine;using System.Collections;using ProtoBuf.Meta;using Com.YourCompany.Project.Proto.Module;using System.IO;using Com.Duoyu001.Proto.Building;using Com.Duoyu001.Proto.Worker;public class TestProto : MonoBehaviour{ // initvoid Start (){byte[] dataFromServ = new byte[]{8, 233, 7, 16, 100, 24, 1}; //these bytes are generated by serverRuntimeTypeModel serializer =BitchSerializer.Create ();System.IO.MemoryStream memStream = new System.IO.MemoryStream ();WorkerInfo w = new WorkerInfo ();serializer.Deserialize (memStream, w, w.GetType ());//asign value to proto modelDebug.Log (w.workerId + ", " + w.buildingId + ", " + w.leftClosingTimeSec);}}运行后Unity控制台输出了worker的信息。

相关文档
最新文档