首页 > 代码库 > Unity3D使用TCP/IP协议,传递protocol buffer消息protobuf-net
Unity3D使用TCP/IP协议,传递protocol buffer消息protobuf-net
原文:http://my.oschina.net/faint/blog/296785
第一部分 dll
1 下面大多数内容,都是使用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/ip
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | using System; using System.IO; using System.Net.Sockets; namespace TcpConnector{ public struct Msg { public int Type; public int Size; public byte [] Content; } public class Connector{ 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; } private 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 type if (msgTypeByte.Length>i){ msgByte[index] = msgTypeByte[i]; } index++; } for (i=0;i<HEAD_SIZE;i++){ // put msg size if (msgTypeByte.Length>i){ msgByte[index+i] = msgSizeByte[i]; } index++; } for (i=0;i<msgSize;i++){ // put msg content if (msgTypeByte.Length>i){ msgByte[index+i] = msgContent[i]; } index++; } stream.Write(msgByte,0,msgByte.Length); stream.Flush(); } } } |
主要用的是TcpClient,NetworkStream,BitConverter.
1 2 3 4 5 6 7 8 9 | TcpClient client = new TcpClient(ip,port); // 获取与服务器连接 NetworkStream stream = client.GetStream(); // 获取连接的流 stream.Read(buf,0,lenght); // 读取至buf stream.Write(buf,0,lenght); // 写至buf BitConverter.GetBytes(data); // 用于将整数转为字节 BitConverter.ToInt32(data,0); // 用于将字节转为整数 stream.Flush(); // 将流中缓存发出,而不等候 stream.Close(); // 关闭流 client.Close(); // 关闭连接 |
第三部分 protobuf-net
FQ下载安装:http://code.google.com/p/protobuf-net/
数据结构编译成dll:
先新建解决方案,新建库,添加下载的full/unity/dll。具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | using System; using ProtoBuf; namespace CSProtoData { [ProtoContract] public class Head { [ProtoMember(1)] public Int32 DataType { get ; set ; } [ProtoMember(2)] public Int64 DataDate { get ; set ; } [ProtoMember(3)] public byte [] DataContent { get ; set ; } } [ProtoContract] public class Number { [ProtoMember(1)] public Int32 Index { get ; set ; } [ProtoMember(2)] public Int64 Value { get ; set ; } } public class Board { [ProtoMember(1)] public Int64 Rank { get ; set ; } [ProtoMember(2)] public string TargetName { get ; set ; } [ProtoMember(3)] public Int64 Number { get ; set ; } } public class Request { [ProtoMember(1)] public string DataType { get ; set ; } [ProtoMember(2)] public Int64 DataDate { get ; set ; } [ProtoMember(3)] public Int32 Start { get ; set ; } [ProtoMember(4)] public Int32 End { get ; set ; } } } |
编译完后,生成dll下面马上用到(同时也要拖放到unity/assets下)。
第三部分 下
因为protobuf-net的序列化和反序列化用的是jit,ios不支持jit,所以需采用编译成dll的方式来解决问题:
vs中,新建命令行程序,添加protobuf-net/full/unity/dll,添加刚生成的dll,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using System; using ProtoBuf; using ProtoSerializer; using CSProtoData; namespace ProtoSerializer { class MainClass { public static void Main( string [] args) { var model = ProtoBuf.Meta.TypeModel.Create(); model.Add( typeof (Head), true ); model.Add( typeof (Number), true ); model.Add( typeof (Board), true ); model.Add( typeof (Request), true ); model.Compile( "CSProtoSerializer" , "CSProtoSerializer.dll" ); } } } |
这里按运行后,会在目录下生成:CSProtoSerializer.dll,一样拖放到unity/assets下。
其中typeof()的,就是proto数据类型,在上半部分有定义的内容。
第四部分 unity代码
执行完以上步骤,unity/assets下应该有这么几个dll:
protobuf-net/full/unity/dll
proto的data的dll(第三部分)
data的序列化的dll(第三部分下,运行后生成的那个)
还有用于tcp连接的dll(第二部分)
那么实际在unity当中调用的代码则是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | using UnityEngine; using System.Collections; using TcpConnector; using ProtoBuf; using CSProtoData; using System.IO; public class testTcp : MonoBehaviour { // Use this for initialization void Start () { Connector conn = new Connector(); bool result = conn.Connect( "127.0.0.1" ,17093); Debug.Log(result); Head head= new Head{}; head.DataType = 2; head.DataDate = 201407312; MemoryStream memStream = new MemoryStream(); ProtoBuf.Serializer.Serialize<CSProtoData.Head>(memStream, head); byte [] x = memStream.ToArray(); conn.Write(1,x); conn.Write(1,x); } // Update is called once per frame void Update () { } } |
新建个script,随便挂在比如camara的组件里即可。
Unity3D使用TCP/IP协议,传递protocol buffer消息protobuf-net