消息头:消息唯一标识,用来区分当前网络请求的类型。登陆就做账号验证,聊天就做消息群发。
一般使用数字表示,字符串比较耗内存。1byte范围为0 ~ 255,2byte范围为0 ~ 65535,消息头一般情况2byte就够了。
消息体:真正传输的数据。
假设1001为登陆请求,1004为聊天功能。
// 假设是收到的消息
byte[] 接收到的消息 = null;
// 创建数组存储消息头数据
byte[] header = new byte[2];
// 给存储消息头的数组赋值
header[0] = 接收到的消息[0];
header[1] = 接收到的消息[1];
// 将存储消息头的数组转换成int类型
int messgeld = BitConverter.ToInt32(header, 0);
// 消息体数据
byte[] body = new byte[接收到的消息.Length - 2];
for (int i = 0; i < 接收到的消息.Length - 2; i++) {
body[i] = 接收到的消息[i + 2];
}
if (messgeld == 1001) {
// 执行登录数据逻辑
} else if (messgeld == 1004) {
// 执行聊天功能
}
服务器和客户端都可以使用Json将复杂的数据序列化成字节数组进行传递。
但服务器和客户端都需要写对应的解析类(客户端一份,服务器一份,且两者的解析类必须一样)。
Protobuffer
用途:和Json相似,功能无非是序列化和反序列化。
在序列化和反序列化上有建立一个体系,使用协议文件生成对应平台的代码。协议文件写完使用软件生成对应平台的解析类。
两者比较:
- 效率高,序列化/反序列化比Json还要快(快20~100倍),产生的字节流比Json还要小(数据可缩小3倍)。做网络传输比Json更省性能。
- 跨语言。
- 提供了程序,方便从Proto文件直接生成编程中可实际使用的类文件。
- 可自动生成序列化和反序列化的接口。
- Protobuffer不可读,Json可读。
Protobuffer 字段规则
字段规则 | 说明 |
---|---|
required | 字段必须出现且仅能出现一次 |
optional | 字段可出现0次或1次 |
repeated | 字段可出现任意次(包括0次)相当于动态数组 |
在每个message中至少要有一个required
类型的字段。
// 类
message Invite {
// 必填,后面为编号
required string host = 1;
required string name = 2;
required string address = 3;
// 选填
optional string info = 4;
}
protobuffer 中的枚举和C#中的一样,类型也是可以嵌套的。
Protobuffer 具体使用
生成解析类工具、pb.dll、ProtoBufUtil.cs
-
先创建一个
ProtoTest.proto
结尾的文件,建议使用VsCode
下载一个protobuf
插件即可。 -
前后端根据需求制定协议。
// 登录 message LoginReq { required string account = 1; repeated string password = 2; }
-
将刚定义好的协议文件使用软件生成指定的解析类(将
.proto
文件放置到Tools\ProtoGenTool\proto下,运行_生成Protocol - 批量
生成的解析类在Tools\ProtoGenTool\cs下)。 -
将生成的解析类拖入项目。
-
将Protobuffer解析库拖入项目(pb.dll、ProtoBufUtil.cs)。
-
Protobuffer序列化反序列化测试。
using UnityEngine; // 生成的解析类 using proto.ProtoTest; public class Test : MonoBehaviour { void Start() { LoginReq login = new LoginReq(); login.account = "SSSS"; login.password = "vv"; // 把对象序列化字节数据 byte[] data = ProtoBufUtils.Serialize(login); var obj = ProtoBufUtils.Deserialize<LoginReq>(data); Debug.LogFormat("账号:{0},密码:{1}", obj.account, obj.password); } }