前言
通过上两篇内容
在Unity中实现TCP通信(一)
在Unity中实现TCP通信(二)
服务端和客户端的TCP通信已经实现了。
但是,在之前的通信中是直接使用了字符串来进行数据的传输。而在实际开发当中,要传输的数据结构是非常复杂的,仅仅使用字符串势必无法满足基本的开发需求。
于是,本篇将阐述一下TCP网络通信中常用的序列化工具,Protobuf。
安装ProtoBuf
Protobuf是Google研发的一种数据序列化工具,它使用Tag技术使数据在序列化成byte时变得非常的小,解析速度也是非常的快,所以很多软件、游戏的网络通讯部分通常都会采用Protobuf来进行数据的传输。
关于Tag技术及Protobuf原理这里不做过多的阐述,有兴趣可以看这篇文章。
安装使用Protobuf以及生成CSharp代码
安装 Python
下载Python27,安装并添加系统变量
在命令行执行"python" 命令,出现下图表示安装成功
安装Protobuf
先在这里下载Protobuf,这是一个编译好的发布版本,如果想自己编译就下载源码即可,我用得是2.5.0
在目录Protobuf-2.5.0\python进入命令行,执行命令"python setup.py install"(进入到python路径然后shift+右键打开命令行即可)
出现下图则安装成功
编译Protobuf
从这里下载Protobuf Net的源码,分别编译ProtoGen,precompile,protobuf-net这3个工程。
将得到这些文件,把它们拷出来,放到和Protobuf同级目录下,这里放到了proto-gen-cs目录下。
由于这个下载地址下载速度堪忧,这里给出编译好的版本,直接下载使用即可。
批量转换.proto文件
在Protobuf同级目录下创建一个空的txt,将其重命名为buildcs.bat(名字随意),如图。
然后在bat文件内输入这么一行代码,保存
1 2 3 4 5 6 7
| @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之类的编辑器打开它,输入如下代码
1 2 3 4 5
| package client;
message test { optional string content = 1; }
|
这里如果不了解proto协议如何编写可以看这篇文章
双击buildcs.bat不出意外,会在cs文件夹下得到一个转换后的csharp代码,长这个样子。
使用生成的代码序列化数据进行Tcp通信
有了proto的代码,就可以将其导入到项目中使用。
客户端
把protobuf-net.dll拖入到unity的plugins文件夹下,把生成的test.cs拖入到unity的scripts文件夹下。
先封装一个工具类,它用于序列化和反序列化数据。
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
| 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); } } }
|
然后把第二篇博客中客户端发送数据的代码改一下
1 2 3 4 5 6 7 8 9 10 11 12 13
| private void onClick() { if(!SocketMgr.Instance.IsConnected) { SocketMgr.Instance.Connect("127.0.0.1", 8888); return; }
client.test sendContent = new client.test(); sendContent.content = inputField.text; byte[] buffer = ProtoBufUtil.ObjectToBytes<test>(sendContent); SocketMgr.Instance.Send(1, buffer); }
|
到这里,只要点击按钮,客户端会把数据序列化成protobuf的格式并发送到服务端。
服务端
添加对protobuf-net.dll(就是上面提到的那个protobuf-net.dll文件)的引用。
把客户端的ProtobufUtil拖到服务端工程目录下,再把test.cs到也拖到工程目录下。
然后把第二篇博客中服务端解析数据的代码改一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 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); Console.WriteLine("消息编号:" + msgCode + ",内容:" + content.content); } }
|
到这里服务端也顺利的使用protobuf来解析数据了,下面开始测试。
测试
还是老套路,先启动服务器,然后客户端连接服务器,成功
然后客户端输入任意内容点击发送
服务端成功的使用Protobuf解析了数据,啪啪啪,此处仍然要有掌声雷动。
结语
到这里protobuf的安装、使用就已经全部写完了,下一篇把最后的心跳机制也写一下,整个TCP网络部分基本就写完了。