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 在需要对结构化数据进行序列化和反序列化的场景中具有很大的优势。

protobuf在游戏通信协议中的使用

protobuf在游戏通信协议中的使用

protobuf在游戏通信协议中的使⽤
原⽂参考blog
通协议中的消息
对游戏项⽬⽽⾔,我们通常会使⽤TCP进⾏前后端的通信协议开发,TCP是字节流协议,所以还需要在⽹络代码⾥把TCP字节流解析成应⽤层需要的⼀条⼀条消息(message)。

⼀条消息包含消息ID和消息内容(payload)。

消息ID主要⽤于告知业务代码后续的⼆进制payload应该解析成什么样的结构,通常为了节省流量,消息ID使⽤整数表⽰。

以登陆消息为例,如下所⽰:
消息ID消息payload
1001登录账号、token等
1002登录状态、访问token等
收发消息流程
⾃定义消息编解码
使⽤protobuf
⼿动解析消息ID和消息结构
使⽤protobuf的反射⽀持
原⽂参考blog。

protobuf的基本用法

protobuf的基本用法

protobuf的基本用法Protobuf是一种开源的序列化框架,它可以将结构化的数据转化成二进制流,从而实现数据的跨平台传输。

在实际开发中,我们经常需要将数据在网络中传输,Protobuf就可以将数据压缩成小巧的二进制格式,大大提高了数据传输效率和安全性。

下面我们来分步骤介绍一下Protobuf的基本用法。

第一步:定义数据结构在使用Protobuf进行数据序列化与反序列化之前,我们需要先定义数据结构。

通常我们使用.proto文件来定义数据结构,这种方式既可以手动编写,也可以使用Protobuf的代码生成器根据已定义的数据类型自动生成。

现在我们来看一个例子:syntax = "proto3";message Person {string name = 1;int32 age = 2;string email = 3;}以上代码定义了一个Person的数据结构,它包含了name、age 和email三个字段。

每个字段都有一个唯一标识符,用来指定字段的顺序和类型。

其中string表示字符串型,int32表示整型。

第二步:编写数据处理代码数据结构定义完成后,我们就可以开始编写数据处理代码了。

使用Protobuf,我们可以将数据转化成二进制格式、从二进制格式中解析数据、or实现数据的压缩和解压。

示例代码如下://将数据转化成二进制格式Person person;person.set_name("John");person.set_age(30);person.set_email("************");string binaryData = person.SerializeAsString();//从二进制格式中解析数据Person newPerson;newPerson.ParseFromString(binaryData);string name = ();int32_t age = newPerson.age();string email = newPerson.email();在以上示例中,我们定义了一个Person对象,设置了该对象的name、age和email属性,并将其转换为二进制数据。

protobuf java 类型

protobuf java 类型

protobuf java 类型Protobuf(Protocol Buffers)是一种用于序列化结构化数据的语言无关、平台无关、可扩展的机制,由Google开发而来。

在Java中使用Protobuf时,需要定义消息的结构和数据类型,然后通过编译器生成相应的Java类。

本文将介绍一些常用的Protobuf Java类型的相关参考内容。

1. 基本类型(Primitive Types):- bool:表示布尔值,可以取true或false。

- int32/int64:表示有符号的32位或64位整数。

- uint32/uint64:表示无符号的32位或64位整数。

- float/double:表示32位或64位浮点数。

- string:表示文本字符串。

- bytes:表示原始字节序列。

2. 枚举类型(Enum Types):- 定义一个枚举类型时,使用"enum"关键字,然后列出枚举值。

- 枚举值必须是唯一的,并且可以使用数值或字符串作为标识。

- 通过枚举值的名称或数值可以进行相互转换。

3. 自定义类型(Custom Types):- message:可以定义复杂的消息类型,包含多个字段。

- 在message中,可以使用嵌套message来表示复杂的数据结构。

- 使用"required"、"optional"或"repeated"关键字来定义字段的属性。

- "required"表示该字段必须出现一次,"optional"表示该字段可以不出现或只出现一次,"repeated"表示该字段可以出现多次。

4. Map类型:- 使用map关键字可以定义一个映射类型,将一个键映射到一个值。

- 键的类型必须是整数或字符串,值的类型可以是任意类型。

- map类型可以使用"repeated"关键字,表示一个键对应多个值。

如何在Java内使用Protobuf

如何在Java内使用Protobuf

如何在Java内使⽤Protobuf⾸先,你需要安装protoBuf的编译器。

假设你已经安装好protobuf的编译器。

新建⼀个maven项⽬,pom内添加如下依赖<dependencies><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.4.0</version></dependency></dependencies>第⼆步,在src/main/java新建proto⽬录。

在⾥⾯写.proto⽂件,声明你对象的格式。

⽐如我的,如果不懂,先抄,看最后结果。

syntax="proto3";package cc.protobuf;option java_package = "cc.protobuf.model";option java_multiple_files=true;option java_outer_classname="AddressBookProtos";message Person{string name = 1;int32 id = 2;string emial = 3;enum PhoneType {MOBILE=0;HOME=1;WORK=3;}message PhoneNumber{string number = 1;PhoneType rtpe = 2;}repeated PhoneNumber phone = 4;message AddressBook{repeated Person people = 4;}}第三步,使⽤protoc根据.proto⽂件⽣成代码。

protobuf java 类型

protobuf java 类型

protobuf java 类型摘要:1.简介2.什么是Protobuf3.为什么使用Protobuf4.Java与Protobuf的结合5.如何在Java中使用Protobuf6.总结正文:1.简介在现代软件开发中,数据交换格式和协议的设计与实现变得越来越重要。

为了简化这一过程,Google开发了一种名为Protocol Buffers(简称Protobuf)的数据序列化格式。

它允许我们在不同语言和平台之间轻松地传输结构化数据。

本文将重点介绍Java中如何使用Protobuf。

2.什么是ProtobufProtocol Buffers是一种轻量级的数据交换格式,用于结构化数据序列化。

它具有易于阅读和编写的特点,同时提供了很好的性能。

Protobuf可以用于各种场景,如RPC(远程过程调用)、数据存储等。

3.为什么使用Protobuf使用Protobuf有许多优点:- 简单:Protobuf具有简单的数据结构,易于理解和实现。

- 高效:Protobuf具有高效的编码和解析性能。

- 可扩展:Protobuf支持数据结构的扩展,方便添加新功能。

- 多语言支持:Protobuf提供了多种编程语言的支持,包括Java、Python、C++等。

4.Java与Protobuf的结合在Java中使用Protobuf,需要借助Google提供的Protobuf Java库。

该库提供了Java语言的序列化/反序列化支持,允许我们在Java中方便地使用Protobuf数据格式。

5.如何在Java中使用Protobuf在Java中使用Protobuf,可以分为以下几个步骤:- 定义数据结构:首先,我们需要定义Java数据结构对应的Protobuf数据结构。

这可以通过使用Protobuf的语法来完成。

例如:```syntax = "proto3";message Person {string name = 1;int32 age = 2;string email = 3;}```- 生成Java代码:使用Protobuf Java编译器(protoc)将Protobuf数据结构编译为Java代码。

java protobuf用法 -回复

java protobuf用法 -回复

java protobuf用法-回复protobuf(Protocol Buffers)是一种跨平台、语言无关的序列化数据结构定义语言。

它由Google开发并于2008年开源。

protobuf的主要目标是提供一种更高效、更简单的方式来处理结构化数据,使得数据传输和存储更加高效。

在本文中,我将向您介绍protobuf的基本使用方法。

1. 安装protobuf首先,您需要安装protobuf。

您可以在protobuf的官方网站(2. 编写.proto文件protobuf使用.proto文件来定义数据结构。

在您的项目目录中创建一个新的.proto文件,并按照protobuf的语法规范定义您的数据结构。

以下是一个简单的例子:protobufsyntax = "proto3";package com.example;message Person {string name = 1;int32 age = 2;repeated string hobbies = 3;}在上面的示例中,我们定义了一个名为Person的message类型,它包含一个名称(name)和年龄(age),以及一个重复出现的字符串数组(hobbies)。

3. 使用protoc编译.proto文件在编写完.proto文件后,我们需要使用protoc编译器将.proto文件编译成相应的代码文件。

打开终端,输入以下命令:protoc java_out=./src/main/java ./path/to/your/proto/file.proto其中,java_out参数指定生成的代码文件的输出目录。

您需要将路径替换为您实际的.proto文件路径。

4. 使用生成的代码在成功编译.proto文件后,protoc编译器将生成一些Java代码文件,以便您在项目中使用。

将这些文件复制到您的项目中相应的包路径下。

现在,您可以在您的Java代码中使用生成的代码来创建和操作protobuf 数据。

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

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

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就有问题。

Unity3Dprotobuf-net使用方式

Unity3Dprotobuf-net使用方式

Unity3Dprotobuf-net使⽤⽅式1、下载2、创建Unity⼯程,创建⼀个Plugins⽂件夹,将protobuf-net解压把⾥⾯得protobuf-net放到Plugins3、创建⼀个名为mcs的⽂本⽂件,⾥⾯写上-unsafe4、重启Unity5、编译⾃动⽣成cs代码⼯具protogen.exe就是刚才⽣成的6、编写.proto⽂件message.proto⾥写⼊message TeamCharacterOne{required uint64 CharacterId = 1;required string CharacterName = 2;required int32 RoleId = 3;required int32 Level = 4;required int32 Ladder = 5;required int32 FightPoint = 6;optional int32 QueueResult = 7;}7、⽣成.cs代码创建⼀个proto.bat⽂件⽂件⾥⾯写⼊@echo offrem 查找⽂件for /f "delims=" %%i in ('dir /b ".\*.proto"') do echo %%irem 转cpp for /f "delims=" %%i in ('dir /b/a "*.proto"') do protoc -I=. --cpp_out=. %%ifor /f "delims=" %%i in ('dir /b/a "*.proto"') do protogen -i:%%i -o:%%~ni.cspause8、把代码放⼊Unity⼯程9、写测试代码using message;using System.Collections;using System.Collections.Generic;using System.IO;using UnityEngine;public class NewBehaviourScript : MonoBehaviour { // Use this for initializationvoid Start () {var a = new TeamCharacterOne();a.CharacterId = 10;a.CharacterName = "fdsafd";var b = Serialize(a);var data = Deserialize<TeamCharacterOne>(b);Debug.Log(data.CharacterName);}// Update is called once per framevoid Update () {}byte[] Serialize(object o){using (MemoryStream ms = new MemoryStream()) {ProtoBuf.Serializer.Serialize(ms, o);byte[] result = new byte[ms.Length];ms.Position = 0;ms.Read(result, 0, result.Length);return result;}}T Deserialize<T>(byte[] b){using (MemoryStream ms = new MemoryStream()) {ms.Write(b, 0, b.Length);ms.Position = 0;return ProtoBuf.Serializer.Deserialize<T>(ms);}}}。

java中使用Protobuf的实例(Demo)

java中使用Protobuf的实例(Demo)

java中使⽤Protobuf的实例(Demo)由于Protobuf受到推崇,故尝试采⽤protobuf来摒弃传统的xml进⾏传输数据。

⾸先,需要下载的关于Protobuf的⽂件:1.到/p/protobuf/downloads/list ,选择其中的win版本下载,我选择的是protoc-2.4.1-win32.zip2.下载⼀个protobuf-java-2.4.1.jar⽂件(注意,要与你刚才下的proto.exe版本相同)然后就开始开发了。

步骤:1.⽤记事本编写⼀个.proto⽂件:}如:我编写的是test.protopackage protobuf;option java_package = "com.sq.protobuf";option java_outer_classname = "FirstProtobuf";message testBuf {required int32 ID = 1;required string Url = 2;}将其放在与刚解压的protoc.exe同级⽬录中。

2.在cmd中,到protoc-2.4.1-win32⽂件夹下,执⾏E:\protoc-2.4.1-win32> protoc.exe --java_out=./ test.proto则可以找到的⼀个⽣成的FirstProtobuf.java⽂件。

3.在MyEclipse中新建⼀个java project,建⽴包com.sq.protobuf,然后将刚才⽣成的FirstProtobuf.java⽂件放在其下⾯。

此时会报错,因为没有引⼊jar包,在package视图下,将protobuf-java-2.4.1.jar引⼊,即可解决问题。

4.建⽴测试⽂件:package com.sq.protobuf.test;import java.io.ByteArrayInputStream;import java.io.InputStream;import java.sql.Blob;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.Statement;import com.google.protobuf.InvalidProtocolBufferException;import com.sq.protobuf.FirstProtobuf;public class Test {public static void main(String[] args) {//序列化过程//FirstProtobuf是⽣成类的名字,即proto⽂件中的java_outer_classname//testBuf是⾥⾯某个序列的名字,即proto⽂件中的message testBufFirstProtobuf.testBuf.Builder builder=FirstProtobuf.testBuf.newBuilder();builder.setID(777);builder.setUrl("shiqi");//testBufFirstProtobuf.testBuf info=builder.build();byte[] result = info.toByteArray() ;String driver = "oracle.jdbc.driver.OracleDriver";String url = "jdbc:oracle:thin:@10.64.59.12:1521/orcl";String user = "parkingsystem";String password = "parkingsystem";try {Class.forName(driver);Connection conn = DriverManager.getConnection(url, user, password);if(!conn.isClosed()){System.out.println("Succeeded connecting to the Database!");//此处只能使⽤prepareStatementPreparedStatement ps = conn.prepareStatement("insert into test(id,test) values (1,?)");//写⼊数据库,要把它改写为流的形式ByteArrayInputStream stream = new ByteArrayInputStream(result);ps.setBinaryStream(1,stream,stream.available());Statement statement = conn.createStatement();Blob blob = null;ps.execute();////////////////上述完成将写⼊数据库的操作,数据库中对应的字段的属性要设置为BlobString sql = "select test from test";ResultSet rs = statement.executeQuery(sql);if(rs.next()){blob = rs.getBlob("test");}byte[] s = blob.getBytes(1,(int)blob.length());FirstProtobuf.testBuf testBuf = FirstProtobuf.testBuf.parseFrom(s);System.out.println(testBuf);conn.close();}}catch(Exception e) {e.printStackTrace();}//反序列化过程try {FirstProtobuf.testBuf testBuf = FirstProtobuf.testBuf.parseFrom(result);System.out.println(testBuf);} catch (InvalidProtocolBufferException e) {e.printStackTrace();}}}发现可以将其序列化,插⼊到数据库,并可以从数据库出取出后,反序列化,内容可以正常显⽰出来。

Unity3D使用TCPIP协议,传递protocolbuffer消息protobuf

Unity3D使用TCPIP协议,传递protocolbuffer消息protobuf

Unity3D使用TCPIP协议,传递protocolbuffer消息protobuf原文:/faint/blog/296785第一部分 dll1 下面大多数内容,都是使用c#编译的dll来实现的。

2 编译为dll后,要拖放到unity3d的Assets里面,才能using 到。

3 有以下类似错误,就是使用了非.net 2.0编译的dll。

注意项目必须是在.net 2.0版本编译的才能正常在unity3d当中使用。

Unhandled Exception: System.TypeLoadException: Could not load type 'System.Runtime.Versioning.TargetFrameworkAttribute' from assembly 'MyModel'4 应该不能用MonoDevelop编译下面会提到的Serializer部分(编译不出dll,会报错)。

需用vs编译。

第二部分 tcp/ip1 2 3 4 5 6 7 8 910111213141516171819 using System;using System.IO;using .Sockets; namespace TcpConnector{ public struct Msg {public int Type;public int Size;public byte [] Content; }public class Connector{2021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 const int HEAD_SIZE = 4;private TcpClient client;NetworkStream stream;public bool Connect( string ip, int port){try {client = new TcpClient(ip,port);stream = client.GetStream();return true ;}catch {return false ;}}public void Disconnect(){stream.Close();client.Close();}private int readType(){byte [] headData = new byte [HEAD_SIZE]; stream.Read(headData,0,headData.Length);int msgType = BitConverter.ToInt32(headData,0); return msgType;}64 6566 6768 6970 71 7273 7475 7677 7879 8081 8283 8485 8687 8889 90 9192 9394 9596 9798 99100 101102103104105106private int readSize(){byte [] headData = new byte [HEAD_SIZE];stream.Read(headData,0,headData.Length);int msgSize = BitConverter.ToInt32(headData,0);return msgSize; } private byte [] readContent( int leghth){ byte [] content = new byte [leghth]; stream.Read(content,0,content.Length);return content;}public Msg Read(){Msg msg = new Msg();msg.Type = readType();msg.Size = readSize(); if (msg.Size > 0) { msg.Content = readContent(msg.Size); } return msg;}public void Write( int msgType, byte [] msgContent){ byte [] msgTypeByte = BitConverter.GetBytes(msgType); int msgSize = HEAD_SIZE+HEAD_SIZE+msgContent.Length;byte [] msgSizeByte = BitConverter.GetBytes(msgSize); int totalSize = HEAD_SIZE+HEAD_SIZE+msgSize;byte [] msgByte = new byte [totalSize];int index = 0;int i = 0;for (i=0;i<HEAD_SIZE;i++){ // put msg typeif (msgTypeByte.Length>i){msgByte[index] = msgTypeByte[i];}index++;}for (i=0;i<HEAD_SIZE;i++){ // put msg sizeif (msgTypeByte.Length>i){msgByte[index+i] = msgSizeByte[i];}index++;}for (i=0;i<msgSize;i++){ // put msg contentif (msgTypeByte.Length>i){msgByte[index+i] = msgContent[i];}index++;}stream.Write(msgByte,0,msgByte.Length);stream.Flush();}}}主要用的是T cpClient ,NetworkStream ,BitConverter. 1 23 45 6789TcpClient client = new TcpClient(ip,port); // 获取与服务器连接 NetworkStream stream = client.GetStream(); // 获取连接的流 stream.Read(buf,0,lenght); // 读取至bufstream.Write(buf,0,lenght); // 写至bufBitConverter.GetBytes(data); // 用于将整数转为字节BitConverter.ToInt32(data,0); // 用于将字节转为整数 stream.Flush(); // 将流中缓存发出,而不等候 stream.Close(); // 关闭流client.Close(); // 关闭连接第三部分 protobuf-netFQ 下载安装: /p/protobuf-net/ 数据结构编译成dll :先新建解决方案,新建库,添加下载的full/unity/dll 。

protobuf在java应用中通过反射动态创建对象(DynamicMessage)

protobuf在java应用中通过反射动态创建对象(DynamicMessage)

protobuf在java应⽤中通过反射动态创建对象(DynamicMessage)---恢复内容开始---最近编写⼀个游戏⽤到protobuf数据格式进⾏前后台传输,苦于protobuf接受客户端的数据时是需要数据类型的如xxx.parseForm(...),这样就要求服务器在接受客户端请求时必须知道客户端传递的数据类型。

由于客户端的请求数据是多种多样的,服务器端⼜不知道客户端的请求到底是哪个类型,这样就使得服务器端编程带来很多⿇烦,甚⾄⼨步难⾏。

难道就没有解决办法了吗,答案当然是有的。

下⾯就说⼀下常⽤的⽅法。

(在看本⽂之前建议先了解protobuf的⼀些基本语法,和基本⽤法)1.第⼀种⽅法也是最简单的⽅法,就是在整个应⽤程序中只定义⼀个proto⽂件,那么所有的请求都是⼀种类型,那么服务器端就不⽤苦恼怎么解析请求数据了,因为不管哪个请求数据都⽤同⼀个对象解析。

如下⾯的列⼦:⾸先贴⼀个PBMessage.proto⽂件//客户端请求以及服务端响应数据协议option java_outer_classname = "PBMessageProto";package com.ppsea.message;import "main/resources/message/DataMsg.proto";message PBMessage{optional int32 playerId = 1; //玩家idrequired int32 actionCode = 2; //操作码idoptional bytes data = 5; //提交或响应的数据optional DataMsg dataMsg = 6; //服务器端推送数据optional string sessionKey = 7; //请求的校验码optional int32 sessionId = 8;//当前请求的标⽰}如上述代码,整个应⽤都基于PBMessage.proto传输,注意到protobuf 语法中 optional修饰符,他表⽰这个字段是⾮必须的,也就是说对于客户端的不同请求,只需要为它填充其请求时⽤到的字段的值即可,其他的字段的值就不⽤管了,这样就可以模拟出各种请求来,那么接下来我们就⽤:PBMessage.parseForm(byte_PBMesage) //byte_PBMesage表⽰客户端请求数据 ,这样请求的解析就完成了。

protobuf 使用场景

protobuf 使用场景

protobuf 使用场景
Protobuf(Protocol Buffers)是一种语言无关、平台无关、可
扩展的序列化数据结构的方法。

以下是Protobuf的一些常见使用场景:
1. 数据存储:Protobuf可以用于将数据序列化后存储在数据库
或文件中,并在需要时进行反序列化。

2. 网络通信:Protobuf可以用于将结构化的数据序列化后在网
络上传输,并在接收端进行反序列化。

它适用于高性能、带宽有限的网络通信场景。

3. API接口定义:Protobuf可以用于定义API接口的消息格式,以便不同语言的系统可以通过该定义生成相应的代码,从而实现跨语言的通信。

4. 分布式系统:Protobuf可以用于在不同的分布式系统之间进
行通信,通过定义共享的数据结构,提高系统之间的互操作性。

5. 日志传输:Protobuf可以用于将日志数据序列化后在系统间
传输,从而提高日志的传输效率和可读性。

6. 缓存数据: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的信息。

相关文档
最新文档