C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信
简介
Protocol Buffer(又称protobuf)是Google开发的一种数据序列化格式,它比XML和JSON更快、更小、更简单。由于最初是用于Google内部的系统和数据通信,并且其生成和解析代码性能优秀,因此被开源出来,可供广泛的应用使用。
Unity 的网络通信有多种方式,传统的网络通信方式使用的是二进制通信,Protocol Buffer 序列化后的数据包十分小巧,带来了传输效率的很大提升。本文介绍了如何使用 C# 库在 Unity 中进行 Protocol Buffer 序列化及网络通信。
使用ProtoBuf进行数据序列化
首先,需要引入 protobuf 的库文件,可以通过NuGet等工具来安装Protobuf-net,它是一个比较普及的C#的protobuf序列化库,有很好的公共库支持,适合Unity项目使用。
打开 Visual Studio 或者 Visual Studio Code 在项目的引用中添加 protobuf 库
using ProtoBuf;
using System;
[ProtoContract]
public class UserInfo
{
[ProtoMember(1)]
public int Id { get; set; }
[ProtoMember(2)]
public string Name { get; set; }
}
上述代码中,我们定义了一个名为 UserInfo 的类,加上 ProtoContract 标签,这是 protobuf 序列化的必要标记。同时,类中的属性也需要使用 ProtoMember 标签标注一下,用来指定属性序列化后的标记数字。
当类规模非常大的时候,我们可以通过 ProtoInclude 标签将已有的消息类型引入到消息基类中,从而减少代码量和工作量。
[ProtoContract]
[ProtoInclude(1, typeof(UserInfo))]
public abstract class BaseMessage
{
}
使用ProtoBuf进行网络通信
在 Unity 中实现 Socket 通信无外乎两个关键步骤:客户端向服务端发送消息、服务端收到消息并进行处理并向客户端回复消息。
客户端向服务端发送消息
客户端向服务端发送消息时,需使用 Socket 建立连接,然后将请求数据序列化后发送到服务端。
public class Client : MonoBehaviour
{
void Start()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888));
UserInfo userInfo = new UserInfo { Id = 1, Name = "Debra" };
byte[] buffer;
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, userInfo);
buffer = ms.ToArray();
}
socket.Send(buffer);
}
}
在上面的代码中,我们首先使用 Socket.Connect() 方法将客户端连接到指定的 IP 和端口上,接着我们创建一个 UserInfo 实例,在下一步中将其序列化成我们期望的二进制格式,最后使用 Socket.Send() 方法将请求数据发送到服务端。
服务端收到消息并进行处理并向客户端回复消息
当服务端接收到客户端的请求消息后,服务端需要先解析该请求消息,~~处理逻辑~~ ,制作响应消息并将响应消息序列化后返回给客户端。
public class Server : MonoBehaviour
{
void Start()
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888));
socket.Listen(0);
Socket clientSocket = socket.Accept();
byte[] buffer = new byte[1024];
int length = clientSocket.Receive(buffer);
byte[] data = new byte[length];
Array.Copy(buffer, data, length);
UserInfo userInfo = null;
using (MemoryStream ms = new MemoryStream(data))
{
userInfo = Serializer.Deserialize<UserInfo>(ms);
}
//处理逻辑
userInfo.Name = userInfo.Name + "hello";
byte[] sendBuffer;
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize(ms, userInfo);
sendBuffer = ms.ToArray();
}
clientSocket.Send(sendBuffer);
clientSocket.Close();
}
}
在上述代码中,首先我们创建一个 Socket 执行 listen 监听,当客户端连接后,则会产生一个新的客户端socket。接着,我们使用客户端socket的 Receive() 方法来接收客户端发来的请求,同样需要将接收到的数据进行反序列化,接下来进行我们期望的业务逻辑处理来生成响应(在这个例子中,只是在UserName 末尾添加了“hello”的字样表示已经处理好了响应)。最后将这个响应数据通过 Socket.Send() 发送给客户端。
示例说明
在示例代码中,我们首先创建了一个 UserInfo 类作为 protobuf 的序列化格式,之后定义了一个 Server 和一个 Client 来表示服务端和客户端。在具体的执行中,服务端首先使用 Socket.Bind() 方法将服务器绑定到指定的端口,接着使用 Socket.Listen() 来启动监听。当客户端连接到服务端时,服务端则会调用 Socket.Accept() 方法并返回一个新的客户端Socket,之后通过该客户端 Socket 来接收客户端发来的请求。服务端处理完逻辑后,将响应数据序列化,并通过客户端Socket.Send() 将响应数据回传给客户端。 客户端则负责将请求数据序列化,并调用 Socket.Send() 方法向服务端发送请求数据。
总结
使用 protobuf 序列化技术来进行网络通信是一种非常良好的解决方案,它克服了二进制数据格式和传送速度之间的矛盾。在Unity中使用protobuf,不仅可以提高我们代码的执行效率,还可以提升我们的通信性能和体验。在实际项目中,借助 protobuf 进行数据序列化来进行通信,不仅可以进行各种尝试和创新,还有助于保障网络通信的质量、稳定性和安全性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#使用Protocol Buffer(ProtoBuf)进行Unity中的Socket通信 - Python技术站