Unity网络通信(part3.序列化和反序列化)
目录
前言
概述
序列化
非字符串类型转字节数组
字符串类型转字节数组
将一个类对象转换为二进制
反序列化
字节数组转非字符串类型
字节数组转字符串类型
将二进制数据转为一个类对象
总结
前言
在网络通信中,我们把想要传递的类对象信息序列化为2进制数据(一般为byte字节数组),再将该2进制数据通过网络传输给远端设备,远端设备获取到该2进制数据后再将其反序列化为对应的类对象。
概述
序列化:
将类对象信息转换为可保存或传输的格式的过程。
反序列化:
与序列化相对,将保存或传输过来的格式转换为类对象的过程。
将C#类对象序列化为xml、json、2进制三种格式的数据保存在本地,达到持久化的目的
再将保存在本地的持久化数据文件反序列化为C#类对象。
和网络通信相关的重要知识点(会在网络通信中频繁使用)
1.BitConverter类:主要用于处理各类型和字节数组间的相互转换
2.Encoding类:主要用于处理字符串类型和字节数组间的相互转换
3.加密相关:了解2进制数据加密的常用手段和思路
本地持久化知识点
1.File类:文件操作类,用于操作文件
2.FileStream类:文件流类,以流的形式进行文件存储读取操作
3.MemoryStrem:内存流对象
4.BinaryFormatter:2进制格式化对象
序列化
非字符串类型转字节数组
关键类:BitConverter
所在命名空间:System
主要作用:除字符串的其它常用类型和字节数组相互转换
byte[] bytes = BitConverter.GetBytes(1);
字符串类型转字节数组
关键类:Encoding
所在命名空间:System.Text
主要作用:将字符串类型和字节数组相互转换,并且决定转换时使用的字符编码类型,网络通信时建议大家使用UTF-8类型
byte[] byte2 = Encoding.UTF8.GetBytes("撒,来细数你的罪恶吧!");
将一个类对象转换为二进制
注意:网络通信中我们不能直接使用数据持久化2进制知识点中的BinaryFormatter 2进制格式化类。因为客户端和服务器使用的语言可能不一样,BinaryFormatter是C#的序列化规则,和其它语言之间的兼容性不好。如果使用它,那么其它语言开发的服务器无法对其进行反序列化,我们需要自己来处理将类对象数据序列化为字节数组。
using System;
using System.Text;
using UnityEngine;public class PlayerInfo
{public int lev;public string name;public short atk;public bool sex;public byte[] GetBytes(){int indexNum = sizeof(int) + //lev int类型 4sizeof(int) + //代表 name字符串转换成字节数组后 数组的长度 4Encoding.UTF8.GetBytes(name).Length + //字符串具体字节数组的长度sizeof(short) + //atk short类型 2sizeof(bool); //sex bool类型 1byte[] playerBytes = new byte[indexNum];int index = 0;//从 playerBytes数组中的第几个位置去存储数据//等级BitConverter.GetBytes(lev).CopyTo(playerBytes, index);index += sizeof(int);//姓名byte[] strBytes = Encoding.UTF8.GetBytes(name);int num = strBytes.Length;//存储的是姓名转换成字节数组后 字节数组的长度BitConverter.GetBytes(num).CopyTo(playerBytes, index);index += sizeof(int);//存储字符串的字节数组strBytes.CopyTo(playerBytes, index);index += num;//攻击力BitConverter.GetBytes(atk).CopyTo(playerBytes, index);index += sizeof(short);//性别BitConverter.GetBytes(sex).CopyTo(playerBytes, index);index += sizeof(bool);return playerBytes;}
}public class Test : MonoBehaviour
{void Start(){//单纯的转换一个变量为字节数组非常的简单//但是我们如何将一个类对象携带的所有信息放入到一个字节数组中呢//我们需要做以下几步//1.明确字节数组的容量(注意:在确定字符串字节长度时要考虑解析时如何处理)PlayerInfo info = new PlayerInfo();info.lev = 1;info.name = "玩家";info.atk = 5;info.sex = false;//得到的 这个Info数据 如果转换成 字节数组 那么字节数组容器需要的容量int indexNum = sizeof(int) + //lev int类型 4sizeof(int) + //代表 name字符串转换成字节数组后 数组的长度 4Encoding.UTF8.GetBytes(info.name).Length + //字符串具体字节数组的长度sizeof(short) + //atk short类型 2sizeof(bool); //sex bool类型 1//2.申明一个装载信息的字节数组容器byte[] playerBytes = new byte[indexNum];//3.将对象中的所有信息转为字节数组并放入该容器当中(可以利用数组中的CopeTo方法转存字节数组)//CopyTo方法的第二个参数代表 从容器的第几个位置开始存储int index = 0;//从 playerBytes数组中的第几个位置去存储数据//等级BitConverter.GetBytes(info.lev).CopyTo(playerBytes, index);index += sizeof(int);//姓名byte[] strBytes = Encoding.UTF8.GetBytes(info.name);int num = strBytes.Length;//存储的是姓名转换成字节数组后 字节数组的长度BitConverter.GetBytes(num).CopyTo(playerBytes, index);index += sizeof(int);//存储字符串的字节数组strBytes.CopyTo(playerBytes, index);index += num;//攻击力BitConverter.GetBytes(info.atk).CopyTo(playerBytes, index);index += sizeof(short);//性别BitConverter.GetBytes(info.sex).CopyTo(playerBytes, index);index += sizeof(bool);}
}
反序列化
字节数组转非字符串类型
关键类:BitConverter
所在命名空间:System
主要作用:除字符串的其它常用类型和字节数组相互转换
byte[] bytes = BitConverter.GetBytes(99);
int i = BitConverter.ToInt32(bytes, 0);
print(i);
字节数组转字符串类型
关键类:Encoding
所在命名空间:System.Text
主要作用:将字符串类型和字节数组相互转换,并且决定转换时使用的字符编码类型,网络通信时建议大家使用UTF-8类型
byte[] bytes2 = Encoding.UTF8.GetBytes("我没有梦想,但我可以守护梦想。");
string str = Encoding.UTF8.GetString(bytes2, 0, bytes2.Length);
print(str);
将二进制数据转为一个类对象
using System;
using System.Text;
using UnityEngine;public class PlayerInfo
{public int lev;public string name;public short atk;public bool sex;public byte[] GetBytes(){int indexNum = sizeof(int) + //lev int类型 4sizeof(int) + //代表 name字符串转换成字节数组后 数组的长度 4Encoding.UTF8.GetBytes(name).Length + //字符串具体字节数组的长度sizeof(short) + //atk short类型 2sizeof(bool); //sex bool类型 1byte[] playerBytes = new byte[indexNum];int index = 0;//从 playerBytes数组中的第几个位置去存储数据//等级BitConverter.GetBytes(lev).CopyTo(playerBytes, index);index += sizeof(int);//姓名byte[] strBytes = Encoding.UTF8.GetBytes(name);int num = strBytes.Length;//存储的是姓名转换成字节数组后 字节数组的长度BitConverter.GetBytes(num).CopyTo(playerBytes, index);index += sizeof(int);//存储字符串的字节数组strBytes.CopyTo(playerBytes, index);index += num;//攻击力BitConverter.GetBytes(atk).CopyTo(playerBytes, index);index += sizeof(short);//性别BitConverter.GetBytes(sex).CopyTo(playerBytes, index);index += sizeof(bool);return playerBytes;}
}
public class Test : MonoBehaviour
{void Start(){//1.获取到对应的字节数组PlayerInfo info = new PlayerInfo();info.lev = 1;info.name = "Player";info.atk = 5;info.sex = false;byte[] playerBytes = info.GetBytes();//2.将字节数组按照序列化时的顺序进行反序列化(将对应字节分组转换为对应类型变量)PlayerInfo info2 = new PlayerInfo();//等级int index = 0;info2.lev = BitConverter.ToInt32(playerBytes, index);index += 4;print(info2.lev);//姓名的长度int length = BitConverter.ToInt32(playerBytes, index);index += 4;//姓名字符串info2.name = Encoding.UTF8.GetString(playerBytes, index, length);index += length;print(info2.name);//攻击力info2.atk = BitConverter.ToInt16(playerBytes, index);index += 2;print(info2.atk);//性别info2.sex = BitConverter.ToBoolean(playerBytes, index);index += 1;print(info2.sex);}
}
总结
- 序列化:将对象转换为字节序列的过程。序列化后的字节流保存了对象的状态以及相关的描述信息,以便在网络上传输或保存在本地文件中。
- 反序列化:将字节序列恢复为对象的过程。客户端从文件或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。