文档章节

Unity3D 使用 TCP/IP 协议,传递 protocol buffer 消息( protobuf-net

F
 FaintX
发布于 2014/07/31 14:43
字数 1017
阅读 2684
收藏 1

第一部分 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

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 = msgContent.Length;
            byte[] msgSizeByte = BitConverter.GetBytes(msgSize);
 
            int totalSize = HEAD_SIZE + HEAD_SIZE + msgSize;
            byte[] msgByte = new byte[totalSize];
 
            int index = 0;
            for (int i = 0; i < HEAD_SIZE; i++){ // put msg type
                if (msgTypeByte.Length > i){
                    msgByte[index] = msgTypeByte[i];
                }
                index++;
            }
 
 
            for (int i = 0; i < HEAD_SIZE; i++){ // put msg size
                if (msgTypeByte.Length > i){
                    msgByte[index + i] = msgSizeByte[i];
                }
                index++;
            }
 
            for (int 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.

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。具体代码如下:

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,代码如下:

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当中调用的代码则是:

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的组件里即可。



© 著作权归作者所有

F
粉丝 2
博文 10
码字总数 5378
作品 0
厦门
私信 提问
加载中

评论(2)

F
FaintX 博主

引用来自“邗孜”的评论

Write 方法是不是写错了。

public void Write(int msgType,byte[] msgContent){
      byte[] msgTypeByte = BitConverter.GetBytes (msgType);
      int msgSize = msgContent.Length;
      byte[] msgSizeByte = BitConverter.GetBytes (msgType);

      int totalSize = HEAD_SIZE + HEAD_SIZE + msgSize;
      byte[] msgByte = new byte[totalSize];

      int index = 0;
      for(int i = 0; i < HEAD_SIZE; i ++){
        if(msgTypeByte.Length > i){
          msgByte[index] = msgTypeByte[i];
        }
        index ++;
      }
      for(int i = 0; i < HEAD_SIZE; i ++){
        if(msgSizeByte.Length > i){
          msgByte[index + i] = msgSizeByte[i];
        }
        index ++;
      }
      for(int i = 0; i < msgSize; i ++){
        if(msgSizeByte.Length > i){
          msgByte[index + i] = msgContent[i];
        }
        index ++;
      }
    }
是是,已修订,多谢!
邗孜
Write 方法是不是写错了。

public void Write(int msgType,byte[] msgContent){
      byte[] msgTypeByte = BitConverter.GetBytes (msgType);
      int msgSize = msgContent.Length;
      byte[] msgSizeByte = BitConverter.GetBytes (msgType);

      int totalSize = HEAD_SIZE + HEAD_SIZE + msgSize;
      byte[] msgByte = new byte[totalSize];

      int index = 0;
      for(int i = 0; i < HEAD_SIZE; i ++){
        if(msgTypeByte.Length > i){
          msgByte[index] = msgTypeByte[i];
        }
        index ++;
      }
      for(int i = 0; i < HEAD_SIZE; i ++){
        if(msgSizeByte.Length > i){
          msgByte[index + i] = msgSizeByte[i];
        }
        index ++;
      }
      for(int i = 0; i < msgSize; i ++){
        if(msgSizeByte.Length > i){
          msgByte[index + i] = msgContent[i];
        }
        index ++;
      }
    }
【专栏精选】网络封包神器protobuf简介

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/zhenghongzhi6/article/details/94589294 本文节选自洪流学堂公众号技...

关尔Manic
07/03
0
0
protobuf,json,xml,binary,Thrift之间的对比

golang 使用 protobuf 的教程 golang使用protobuf 一条消息数据,用protobuf序列化后的大小是json的10分之一,xml格式的20分之一,是二进制序列化的10分之一,总体看来ProtoBuf的优势还是很明...

mickelfeng
2018/11/19
405
0
在项目中使用Protobuf协议实现数据传输(二)

上篇已经简单的分析了什么是ProtoBuf协议的优缺点、简单的环境配置、项目中的简单使用和一些编写.Proto文件的注意点,下面我们更加深入一下ProtoBuf的语法及高级使用(非常感谢Carson_Ho大神...

大荣言午
2018/05/31
0
0
android使用protobuf实现网络订单管理功能

在新版本的Beetle.NetPackage开源组件中集成了对Protobuf的支持,在android下可以简单地使用Beetle.NetPackage实现基于Protobuf的TCP通讯数据交互.下详细讲解实现一个网络订单管理功能的过程....

泥水佬
2013/09/08
3.2K
0
[IBM DW] Google Protocol Buffer 的使用和原理

什么是 Google Protocol Buffer? 假如您在网上搜索,应该会得到类似这样的文字介绍: Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有...

红薯
2010/11/21
3.5K
6

没有更多内容

加载失败,请刷新页面

加载更多

Jenkins World 贡献者峰会及专家答疑展位

本文首发于:Jenkins 中文社区 原文链接 作者:Marky Jackson 译者:shunw Jenkins World 贡献者峰会及专家答疑展位 本文为 Jenkins World 贡献者峰会活动期间的记录 Jenkins 15周岁啦!Jen...

Jenkins中文社区
30分钟前
8
0
杂谈:面向微服务的体系结构评审中需要问的三个问题

面向微服务的体系结构如今风靡全球。这是因为更快的部署节奏和更低的成本是面向微服务的体系结构的基本承诺。 然而,对于大多数试水的公司来说,开发活动更多的是将现有的单块应用程序转换为...

liululee
45分钟前
7
0
OSChina 周二乱弹 —— 我等饭呢,你是不是来错食堂了?

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @ 自行车丢了:给主编推荐首歌 《クリスマスの夜》- 岡村孝子 手机党少年们想听歌,请使劲儿戳(这里) @烽火燎原 :国庆快来,我需要长假! ...

小小编辑
今天
460
9
玩转 Springboot 2 之热部署(DevTools)

Devtools 介绍 SpringBoot 提供了热部署的功能,那啥是热部署累?SpringBoot官方是这样说的:只要类路径上的文件发生更改,就会自动重新启动应用程序。在IDE中工作时,这可能是一个有用的功能...

桌前明月
今天
6
0
CSS--列表

一、列表标识项 list-style-type none:去掉标识项 disc:默认实心圆 circle:空心圆 squire:矩形 二、列表项图片 list-style-img: 取值:url(路径) 三、列表项位置 list-style-position:...

wytao1995
今天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部