【Unity】 在Unity中实现Tcp通讯(3)—— ProtoBuf

通过上两篇内容

https://blog.csdn.net/s_GQY/article/details/106187350

https://blog.csdn.net/s_GQY/article/details/106192109

服务端和客户端的通讯已经实现了。

但是,在之前的通讯中是直接使用了字符串来进行数据的传输。

而在实际开发当中,要传输的数据结构是非常的复杂的,仅仅使用字符串势必无法满足基本的开发需求。

于是,本篇将来阐述一下Tcp网络通讯中常用的序列化工具,Protobuf。

Protobuf是Google研发的一种数据序列化工具,它使用Tag技术使数据在序列化成byte时变得非常的小,解析速度也是非常的快,所以很多软件、游戏的网络通讯部分通常都会采用Protobuf来进行数据的传输。

关于Tag技术及Protobuf原理这里不做过多的阐述,有兴趣可以看这篇文章

下面开始进行Protobuf相关的讲解。

一.安装使用protobuf以及生成CSharp代码

1.安装 Python

下载python27,安装并添加系统变量

在命令行执行"python" 命令,出现下图表示安装成功

2.安装Protobuf

先在这里下载Protobuf,这是一个编译好的发布版本,如果想自己编译就下载源码即可,我用得是2.5.0

在目录Protobuf-2.5.0\python进入命令行,执行命令"python setup.py install"(进入到python路径然后shift+右键打开命令行即可)

出现下图则安装成功

3.下载Protobuf Net编译proto gen

这里下载Protobuf Net的源码,分别编译ProtoGen,precompile,protobuf-net这3个工程

将得到这些文件,把它们拷出来,放到和Protobuf同级目录下,这里放到了proto-gen-cs目录下

由于这个下载地址下载速度堪忧,这里给出编译好的版本,直接下载使用即可

4.编写bat程序,批量转换.proto文件

在Protobuf同级目录下创建一个空的txt,将其重命名为buildcs.bat(名字随意),如图

然后bat文件内输入这么一行代码,保存

@echo off

set Path=proto-gen-cs\protogen.exe

for /f "delims=" %%i in ('dir  /b Proto "proto/*.proto"') do %Path% -i:proto/%%i -o:cs/%%~ni.cs

pause

proto文件夹下创建测试proto协议,新建一个空txt,重命名为test.proto

使用pad++或者sublime之类的编辑器打开它,输入如下代码

package client;

message test {
    optional string content = 1;                    //name
}

这里如果不了解proto协议如何编写可以看这篇文章

双击buildcs.bat不出以为,会在cs文件夹下得到一个转换后的csharp代码,长这个样子


 

二.使用生成的代码序列化数据,进行Tcp通讯

有了proto的代码,就可以将其导入到项目中使用。

1.客户端:

把protobuf-net.dll拖入到unity的plugins文件夹下,把生成的test.cs拖入到unity的scripts文件夹下

先封装一个工具类,它用于序列化和反序列化数据

using System;
using ProtoBuf;
using System.IO;


public class ProtoBufUtil
{
    public static byte[] ObjectToBytes<T>(T instance)
    {
        try
        {
            byte[] array;
            if (instance == null)
            {
                array = new byte[0];
            }
            else
            {
                MemoryStream memoryStream = new MemoryStream();
                Serializer.Serialize(memoryStream, instance);
                array = new byte[memoryStream.Length];
                memoryStream.Position = 0L;
                memoryStream.Read(array, 0, array.Length);
                memoryStream.Dispose();
            }

            return array;

        }
        catch (Exception ex)
        {

            return new byte[0];
        }
    }

    public static T BytesToObject<T>(byte[] bytesData, int offset, int length)
    {
        if (bytesData.Length == 0)
        {
            return default(T);
        }
        try
        {
            MemoryStream memoryStream = new MemoryStream();
            memoryStream.Write(bytesData, 0, bytesData.Length);
            memoryStream.Position = 0L;
            T result = Serializer.Deserialize<T>(memoryStream);
            memoryStream.Dispose();
            return result;
        }
        catch (Exception ex)
        {
            return default(T);
        }
    }
}

然后把在第二篇博客客中的客户端发送数据的代码改一下

private void onClick()
{
        if(!SocketMgr.Instance.IsConnected)
	{
            SocketMgr.Instance.Connect("127.0.0.1", 8888);
	    return;
	}

	client.test sendContent = new client.test();//创建protobuf序列化实例
	sendContent.content = inputField.text;//对应字段赋值
	byte[] buffer = ProtoBufUtil.ObjectToBytes<test>(sendContent);//序列化
	SocketMgr.Instance.Send(1, buffer);//发送
}

到这里,只要点击按钮,客户端会把数据序列化成protobuf的格式并发送到服务端

2.服务端:

添加对protobuf-net.dll(就是上面提到的那个protobuf-net.dll文件)的引用

把客户端的ProtobufUtil拖到服务端工程目录下,再把test.cs到也拖到工程目录下

然后把在第二篇博客客中的服务端解析数据的代码改一下

private void CheckReceiveBuffer(object state)
{
    lock (m_ReceiveQueue)
    {
        if (m_ReceiveQueue.Count < 1) return;
        byte[] buffer = m_ReceiveQueue.Dequeue();
        byte[] msgContent = new byte[buffer.Length - 2];
        ushort msgCode = 0;

        using (MemoryStream ms = new MemoryStream(buffer))
        {
            byte[] msgCodeBuffer = new byte[2];
            ms.Read(msgCodeBuffer, 0, msgCodeBuffer.Length);
            msgCode = BitConverter.ToUInt16(msgCodeBuffer, 0);
            ms.Read(msgContent, 0, msgContent.Length);
        }

        test content = ProtoBufUtil.BytesToObject<test>(msgContent, 0, msgContent.Length);//调用protobuf,把数据反序列化为test对象
        Console.WriteLine("消息编号:" + msgCode + ",内容:" + content.content);
    }
}

到这里服务端也顺利的使用protobuf来解析数据了,下面开始测试

 

3.测试:

还是老套路,先启动服务器,然后客户端连接服务器,成功

然后客户端输入任意内容点击发送

服务端成功的使用Protobuf解析了数据,啪啪啪,此处仍然要有掌声雷动


 

三.结束

到这里protobuf的安装,使用就已经全部写完了,下一篇就开始进行心跳机制的讲解,各位再见!

猜你喜欢

转载自blog.csdn.net/s_GQY/article/details/106328210