zoukankan      html  css  js  c++  java
  • 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

    翻墙下载安装: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 { getset; }
            [ProtoMember(2)]
            public Int64 DataDate { getset; }
            [ProtoMember(3)]
            public byte[] DataContent { getset; }
        }
     
        [ProtoContract]
        public class Number
        {
            [ProtoMember(1)]
            public Int32 Index { getset; }
            [ProtoMember(2)]
            public Int64 Value { getset; }
        }
     
        public class Board
        {
            [ProtoMember(1)]
            public Int64 Rank { getset; }
            [ProtoMember(2)]
            public string TargetName { getset; }
            [ProtoMember(3)]
            public Int64 Number { getset; }
        }
     
        public class Request
        {
            [ProtoMember(1)]
            public string DataType { getset; }
            [ProtoMember(2)]
            public Int64 DataDate { getset; }
            [ProtoMember(3)]
            public Int32 Start { getset; }
            [ProtoMember(4)]
            public Int32 End { getset; }
        }
    }

    编译完后,生成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的组件里即可。

  • 相关阅读:
    【原】git常见用法
    【转】EDID的简介和解析
    rsa公钥和私钥的生成
    往redis中存储数据是利用pipeline方法
    对于接口文档个的说明内容包括哪些
    blueprint的使用
    flask中如何生成迁移文件
    flask中自定义过滤器
    jsonify
    flask自定义处理错误方法
  • 原文地址:https://www.cnblogs.com/123ing/p/3951642.html
Copyright © 2011-2022 走看看