Unity3D & Java 基于 Protobuf 通信实现

Unity3D & Java 基于 Protobuf 通信实现

最近研究Unity3D,同时需要给游戏制定一套通信协议。因为本人是后端出生,对C#的 Socket相关通信框架不太熟悉,经过几天的学习,终于搞定了。在这里公布出来,大家可以共同学习,少走弯路。

本文重点:演示怎么解析和发送协议。

技术选型


服务端1
Java7
netty 4
客户端2
C#
SuperSocket.ClientEngine https://clientengine.codeplex.com/

它是从SuperSocket中分离出来的,不人性的是竟然没使用教程

通信协议3
Protobuf https://github.com/google/protobuf/
因为Protobuf 官方只支持 Java,C++,Pythone语言,C#需要第三方支持
protobuf-csharp https://code.google.com/p/protobuf-csharp-port/

Protobuf 相关的使用,请自行Gooogle,后面的代码会展示相关API, Goole打不开买一个代理一个月20RMB

开发前准备



协议解析,无论任何语言协议解析在通信中使用中都是必须的。要成功的解析协议,必须先搞清楚协议是如何制定的。

Protobuf 是基于 变长消息头(length) + 消息体(body)

Proto生成

message Request {
    required string command = 1;
    required string data = 2;
}

message Response {
    required string command = 1;
    required string data = 2;
}

至于怎么生成,我这里就不给出详细方式了,通过Protobuf资料,有详细说明。

客户端代码


        public static DataEventArgs buffer = new DataEventArgs(); 

        public static int count = 0;

        public static void Main (string[] args)
        {

            buffer.Data = new byte[8192]; //8 KB
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8001);

            //supersocket clientengine
            AsyncTcpSession client = new AsyncTcpSession (endPoint);
            client.Connected += OnConnected;
            client.DataReceived += OnDataReceive; //重点解析在这里

            //连接服务器
            client.Connect ();

            //构造Message,属性Protobuf的人应该都能看懂
            Request.Builder builder = Request.CreateBuilder ();
            builder.SetCommand ("110");
            builder.SetData ("1231231232131");

            Request request = builder.BuildPartial ();
            sendMessage (client, request);

            Thread.Sleep (30000);
        }

        public static void OnConnected(Object sender, EventArgs e)
        {
            Console.WriteLine ("connect to server finish.");
        }

        /**
        * 这里 C# 的实现和Protobuf 官方给的Java实现是一样的
        */
        public static void sendMessage(AsyncTcpSession client, Request request)
        {
            using(MemoryStream stream = new MemoryStream())
            {
                CodedOutputStream os = CodedOutputStream.CreateInstance(stream);
                //一定要去看它的代码实现,
                os.WriteMessageNoTag(request);
                /**
                * WriteMessageNoTag 等价于 WriteVarint32, WriteByte(byte[])
                * 也就是:变长消息头 + 消息体
                */

                os.Flush();

                byte[] data = stream.ToArray();
                client.Send ( new ArraySegment<byte>(data) );
            }
        }

        /**
        * 协议解析,把这里搞明白了,就没白看
        */
        public static void OnDataReceive(Object sender, DataEventArgs e)
        {
            //DataEventArgs 里面有 byte[] Data是从协议层接收上来的字节数组,需要程序端进行缓存
            Console.WriteLine ("buff length: {0}, offset: {1}", e.Length, e.Offset);
            if( e.Length <= 0 )
            {
                return;
            }

            //把收取上来的自己全部缓存到本地 buffer 中
            Array.Copy (e.Data, 0, buffer.Data, buffer.Length, e.Length);
            buffer.Length += e.Length;

            CodedInputStream stream = CodedInputStream.CreateInstance (buffer.Data);
            while ( !stream.IsAtEnd )
            {
                //标记读取的Position, 在长度不够时进行数组拷贝,到下一次在进行解析
                int markReadIndex = (int)stream.Position;

                //Protobuf 变长头, 也就是消息长度
                int varint32 = (int)stream.ReadRawVarint32();
                if( varint32 <= (buffer.Length - (int)stream.Position) )
                {
                    try
                    {
                        byte[] body = stream.ReadRawBytes (varint32);

                        Response response = Response.ParseFrom (body);
                        Console.WriteLine("Response: " + response.ToString() + ", count: " + (++count));
                        //dispatcher message, 这里就可以用多线程进行协议分发

                    }catch(Exception exception)
                    {
                        Console.WriteLine(exception.Message);
                    }
                }
                else
                {
                    /**
                    * 本次数据不够长度,缓存进行下一次解析
                    */
                    byte[] dest = new byte[8192];
                    int remainSize = buffer.Length - markReadIndex;
                    Array.Copy(buffer.Data, markReadIndex, dest, 0, remainSize);

                    /**
                     * 缓存未处理完的字节
                     */
                    buffer.Data = dest;
                    buffer.Offset = 0;
                    buffer.Length = remainSize;

                    break;
                }
            }
        }

后记



客户端完整代码打包:http://download.csdn.net/detail/zeus_9i/8748899

  • Unity3D Java 基于 Protobuf 通信实现

    • 技术选型
    • 开发前准备
    • Proto生成
    • 客户端代码
    • 后记
时间: 2024-10-12 23:34:48

Unity3D & Java 基于 Protobuf 通信实现的相关文章

基于networkcomms V3通信框架的c#服务器与java客户端进行通信之Protobuf探讨

在上一篇 基于networkcomms V3通信框架的c#服务器与java客户端进行通信探讨  中探讨了在C#端与Java端通信中传递字符,有朋友提到如果传递int类型的整数,会出现编码的问题. 到网上找到了一篇文章< 使用protobuf进行C#与Java通信 >进行学习 ,使用protobuf进行编码,传递数据,好像这样可以避免编码的问题. (虽然编码问题解决了,但是粘包问题并没有解决,有经验的朋友介绍下怎样解决粘包的问题) 服务器端基于networkcomms V3 C#通信框架. ne

[java]基于UDP的Socket通信Demo

java课编程作业:在老师给的demo的基础上实现客户端发送数据到服务器端,服务器端接受客户端后进行数据广播. 整体功能类似于聊天室,代码部分不是太难,但是在本机测试的时候出现这样的问题: 服务端通过将每一个Socket客户端的IP存入Set集合,每次接受到数据后都向当前所有的IP转发.但是本机演示的时候所有开的ChatClient客户端都是同一IP,怎么测试呢? 解决办法就是本机测试时候服务端向多个不同的端口转发就好了,这样跑起来的客户端是在不同端口上进行监听的(只是为了实现广播,实际应用下还

Golang、Php、Python、Java基于Thrift0.9.1实现跨语言调用

目录: 一.什么是Thrift? 1) Thrift内部框架一瞥 2) 支持的数据传输格式.数据传输方式和服务模型 3) Thrift IDL 二.Thrift的官方网站在哪里? 三.在哪里下载?需要哪些组件的支持? 四.如何安装? 五.Golang.Java.Python.PHP之间通过Thrift实现跨语言调用 1) Golang 客户端和服务端的实现及交互 2) python 客户端的实现与golang 服务端的交互 3) php 客户端的实现与golang 服务端的交互 4) java

(转)基于即时通信和LBS技术的位置感知服务(二):XMPP协议总结以及开源解决方案

在<基于即时通信和LBS技术的位置感知服务(一):提出问题及解决方案>一文中,提到尝试使用XMPP协议来实现即时通信.本文将对XMPP协议框架以及相关的C/S架构进行介绍,协议的底层实现不再本文的讨论范围. 一.什么是XMPP? 介 绍XMPP之前,我们先来聊聊GTalk.GTalk是Google推出的IM(Instant Messaging,即时通讯)软件,类似于QQ和MSN.从技术角度来说,GTalk与QQ和MSN的差异是使用了不同的通讯协议,QQ使用了自己的私 有协议(未公开),MSN也

在Unity3D中基于订阅者模式实现事件机制

??各位朋友,大家好,欢迎大家关注我的博客,我是秦元培,我的博客地址是http://qinyuanpei.com.今天博主想和大家分享的是在Unity3D中基于订阅者模式实现消息传递机制,我们知道Unity3D中默认提供了一种消息传递机制SendMessage,虽然SendMessage使用起来的确非常简单,可是它的这种简单是建立在付出一定的代价的基础上的.经常有朋友提及不同的模块间如何进行通信的问题,可能答案最终会落到单例模式.委托和事件机制这些关键词上,在这种情况下本文所探讨的内容可能会帮助

转一篇Unity客户端与Java服务器的通信

转自:http://www.programering.com/a/MTNxYDMwATQ.html A few days ago a friend asked me about Unity3D inside Protobuf, was something to write this off until now, feel shy. In this paper, the test environment: System: WINDOWS 7 (third, 6), OS (fourth) X 10

JAVA基于AE调用GP实现泰森多边形

public void CreatVoronoi(){ try { GeoProcessor gp=new GeoProcessor(); gp.setOverwriteOutput(true); CreateThiessenPolygons createThiessen=new CreateThiessenPolygons(); createThiessen.setInFeatures("F:/db/pts.shp") createThiessen.setOutFeatureClas

Java实现串口通信的小样例

用Java实现串口通信(windows系统下),须要用到sun提供的串口包 javacomm20-win32.zip.当中要用到三个文件,配置例如以下: 1.comm.jar放置到 JAVA_HOME/jre/lib/ext; 2.win32com.dll放置到 JAVA_HOME/bin; 3.javax.comm.properties 两个地方都要放 jre/lib(也就是在JAVA目录下的jre) JAVA_HOME/jre/lib 说一下我应用的环境.电子秤称重时,计算机通过串口给称重控

java NIO socket 通信实例

java Nio 通信与Bio通信主要不同点: 1.Nio中的单个channel即可支持读操作也可以支持写操作,而bio中读操作要用inputstream,写操作要outputstream. 2.nio 采用byteBuffer 作为内存缓存区,向channel里写或者度操作,bio基本是用byte[] 3.nio采用 selector组件轮询读取就绪channel 服务端demo代码: package com.my.socket3; import java.io.ByteArrayOutput