Unity - serialize and deserialize binary data

Data transmitted in network communication

        in network communication

        We serialize the class object information we want to pass into binary data (usually a byte array)

        Then transmit the binary data to the remote device through the network

        After obtaining the binary data, the remote device deserializes it into the corresponding class object

 Serialization and deserialization

        Serialization:

                The process of converting class object information into a format that can be saved or transmitted

        Deserialize:

                As opposed to serialization, the process of converting a saved or transmitted format into a class object

Data Persistence Binary

        Network communication related

                1.BitConverter class: mainly used to handle the conversion between various types and byte arrays

                2. Encoding class: mainly used to handle the conversion between string types and byte arrays

                3. Encryption related: understand the common means and ideas of binary data encryption

        

        Local persistence knowledge points:

                1.File class: file operation class, used to operate files

                2. FileStream class: file stream, file storage read operation in the form of stream

                3.MemoryStrem: memory stream object

                4.BinaryFormatter: binary format object

        In network development, we will not use the BinaryFormatter class to serialize and deserialize data because the development languages ​​of the client and server are different in most cases. The data serialized by the BinaryFormatter class is not compatible with other languages.

Serialization

        Non-string type to byte array

                main effect:

                        Conversion between other commonly used types and byte arrays except strings

Namespace: using System

        Convert a class object (construct) to binary

    //构建一个构造体存储玩家信息
    public class PlayerInfo
    {
        public int lev;
        public string playerName;
        public short atk;
        public bool sex;
    }

        

                1. Specify the capacity of the byte array (note: when determining the byte length of the string, consider how to deal with it when parsing)

        PlayerInfo info = new PlayerInfo();
        info.lev = 10;
        info.playerName = "缘笙箫";
        info.atk = 88;
        info.sex = false;

        //得到的这个info数据,如果想要转换成为字节数组,那么字节数组容器需要的容量就要提前计算出来
        int indexNum = sizeof(int) +
                       sizeof(int) + //这里的int代表的是字符串的长度,因为UTF-8是可以有多个取值的在存储这个数据的时候要将UTF-8的值传入,方便反序列化的时候确定字符串的长度
                       Encoding.UTF8.GetBytes(info.playerName).Length +
                       sizeof(short) +
                       sizeof(bool);

                2. Declare a byte array container for loading information

byte[] playerBytes = new byte[indexNum];

                3. Convert all the information in the object into a byte array and put it into the container (you can use the CopeTo method in the array to dump the byte array)

                The second parameter of the CopyTo method represents, from which position of the container to start storing

        int index = 0;     //从 playerBytes数组的第几个位置开始存储数据

        //等级
        BitConverter.GetBytes(info.lev).CopyTo(playerBytes, index);
        index += sizeof(int);           //下标进行移动

        //姓名
        byte[] strBytes = Encoding.UTF8.GetBytes(info.playerName);
        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);

                 It can also be written directly in the constructor, which is convenient to call, without having to write it again every time

public class PlayerInfo
{
    public int lev;
    public string name;
    public short atk;
    public bool sex;

    public byte[] GetBytes()
    {
        int indexNum = sizeof(int) + //lev int类型  4
                      sizeof(int) + //代表 name字符串转换成字节数组后 数组的长度 4
                      Encoding.UTF8.GetBytes(name).Length + //字符串具体字节数组的长度
                      sizeof(short) + //atk short类型 2
                      sizeof(bool); //sex bool类型 1

        byte[] 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;
    }
}

Summarize

        Binary serialization of class objects

                1.BitConverter converts non-string type variables to byte arrays

                2. Encoding.UTF8 converts a variable of string type to a byte array (note: in order to consider deserialization, we serialize the length of the string byte array before dumping binary and serializing the string)

        conversion process

                1. Specify the capacity of the byte array

                2. Declare a byte array container for loading information

                3. Convert all the information in the object into a byte array and put it into the container (use the CopeTo method in the array to dump the byte array)

        base class (write)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

//抽象类
public abstract class BaseData
{
    /// <summary>
    /// 用于子类重写的虚方法    获取字节数组的容量
    /// </summary>
    /// <returns>获取字节数组的容量</returns>
    public abstract int GetBytesNum();

    /// <summary>
    /// 返回字节数组
    /// </summary>
    /// <returns>字节数组</returns>
    public abstract byte[] Writeing();
   
    /// <summary>
    /// 将整短形数据转化为二进制并且存入字节数组当中
    /// </summary>
    /// <param name="bytes">字节数组</param>
    /// <param name="shortData">需要存入的整短型</param>
    /// <param name="index">下标编号,ref代表数据在内部进行改变了,外面也跟在改变</param>
    protected  void WriteShort(byte[] bytes,short shortData,ref int index)
    {
        BitConverter.GetBytes(shortData).CopyTo(bytes, index);
        index += sizeof(short);
    }

    protected  void WriteData(byte[] bytes,BaseData Data, ref int index)
    {
        Data.Writeing().CopyTo(bytes, index);
        index += Data.GetBytesNum();
    }

    protected  void WriteInt(byte[] bytes, int IntData, ref int index)
    {
        BitConverter.GetBytes(IntData).CopyTo(bytes, index);
        index += sizeof(int);
    }

    protected  void Writelong(byte[] bytes, short longData, ref int index)
    {
        BitConverter.GetBytes(longData).CopyTo(bytes, index);
        index += sizeof(long);
    }

    protected  void Writestring(byte[] bytes, string stringData, ref int index)
    {
        //先存储string字节数组的长度
        byte[] strBytes = Encoding.UTF8.GetBytes(stringData);
        WriteInt(bytes, strBytes.Length, ref index);
        //BitConverter.GetBytes(strBytes.Length).CopyTo(bytes, index);
        //index += sizeof(int);

        //再存 string字节数组
        strBytes.CopyTo(bytes, index);
        index += strBytes.Length;
    }

    protected  void WriteBool(byte[] bytes,bool boolData, ref int index)
    {
        BitConverter.GetBytes(boolData).CopyTo(bytes, index);
        index += sizeof(bool);
    }
}

        call (write)

using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

public class PlayerATK : BaseData
{
    public int atk;


    public override int GetBytesNum()
    {
        return sizeof(int);
    }

    public override byte[] Writeing()
    {
        int index = 0;
        byte[] bytes = new byte[GetBytesNum()];

        WriteInt(bytes, atk, ref index);

        return bytes;
    }
}

public class Player : BaseData
{

    public int lev;
    public PlayerATK aTK;
    public string name;

    public override int GetBytesNum()
    {
        return sizeof(int) +
               aTK.GetBytesNum() +
               sizeof(int) +
               Encoding.UTF8.GetBytes(name).Length;
    }

    public override byte[] Writeing()
    {
        int index = 0;
        byte[] bytes = new byte[GetBytesNum()];

        WriteInt(bytes, lev, ref index);
        WriteData(bytes, aTK, ref index);
        Writestring(bytes, name, ref index);

        return bytes;
    }
}

public class Test : MonoBehaviour
{
    
    void Start()
    {
        Player player = new Player();
        player.lev = 1;
        player.aTK = new PlayerATK();
        player.aTK.atk = 4;
        player.name = "gfqig";

        byte[] bytes = player.Writeing();
    }

  
}

deserialization

        Byte array to non-string type

                Key class: BitConverter

                Namespace: using System

                Main function: Convert between other commonly used types and byte arrays except strings

        byte[] bytes = BitConverter.GetBytes(99);
        int i = BitConverter.ToInt32(bytes, 0);
        print(i);

        Byte array conversion of non-string type

                Key class: Encoding        

                Namespace: using System.Text

                Main function: convert string type and byte array to each other, and determine the character encoding type used during conversion. UTF-8 is recommended for network communication


        byte[] bytes2 = Encoding.UTF8.GetBytes("yhtgjn");
        string str = Encoding.UTF8.GetString(bytes2, 0, bytes2.Length);
        print(str);

 

 

        Convert binary data to a class object

                1. Get the corresponding byte array      

        PlayerInfo info = new PlayerInfo();
        info.lev = 5;
        info.playerName = "yuan";
        info.atk = 88;
        info.sex = false;


        byte[] playerBytes = info.GetBytes();

                

                2. Deserialize the byte array in the order of serialization (convert the corresponding byte group into the corresponding type variable)

        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.playerName = Encoding.UTF8.GetString(playerBytes, index, length);
        index += length;
        print(info2.playerName);
        //攻击力
        info2.atk = BitConverter.ToInt16(playerBytes, index);
        index += 2;
        print(info2.atk);
        //性别
        info2.sex = BitConverter.ToBoolean(playerBytes, index);
        index += 1;
        print(info2.sex);

 

Summarize

        Binary deserialization of class objects

                1.BitConVerter converts the byte array to a variable of a non-string type

                2. Encoding.UTF8 converts the byte array to a variable of string type (note: read the length first, then read the string)

        The conversion process is

                1. Get the corresponding byte array

                2. Deserialize the byte array in the order of serialization (convert the corresponding byte group into the corresponding type variable)

        base class (read)


    /// <summary>
    /// 反序列化方法,将字节数组信息提取到对象的变量中,读取顺序和序列化时一至
    /// </summary>
    /// <param name="bytes">传入字节数组</param>
    /// <param name="beginIndex">从该字节数组的第几个位置开始解析,默认是0</param>
    /// <returns></returns>
    public abstract int Reading(byte[] bytes,int beginIndex = 0);


    /// <summary>
    /// 读取整数字形
    /// </summary>
    /// <param name="bytes">字节串</param>
    /// <param name="index">下标</param>
    /// <returns>整型</returns>
    protected int ReadInt(byte[] bytes,ref int index)
    {
        int value = BitConverter.ToInt32(bytes, index);
        index += sizeof(int);
        return value;
    }

    protected short ReadShort(byte[] bytes, ref int index)
    {
        short value = BitConverter.ToInt16(bytes, index);
        index += sizeof(short);
        return value;
    }

    protected bool ReadBool(byte[] bytes, ref int index)
    {
        bool value = BitConverter.ToBoolean(bytes, index);
        index += sizeof(bool);
        return value;
    }

    protected string ReadString(byte[] bytes, ref int index)
    {
        //先获取到字符串的长度
        int length = ReadInt(bytes, ref index);
        //index += sizeof(int);

        //再去将字符串给转换出来
        string value = Encoding.UTF8.GetString(bytes, index, length);
        index += length;
        return value;
    } 

    //T代表是泛型,where代表给这个泛型加个范围只能是BaseData里面的类型
    protected T ReadData<T>(byte[] bytes, ref int index) where T:BaseData,new()
    {
        T value = new T();     
        index += value.Reading(bytes,index);
        return value;
    }

        call(read)


    public override int Reading(byte[] bytes, int beginIndex = 0)
    {
        int index = beginIndex;
        atk = ReadInt(bytes, ref index);
        return index - beginIndex;
    }

    public override int Reading(byte[] bytes, int beginIndex = 0)
    {
        int index = beginIndex;
        
        lev = ReadInt(bytes, ref index);
        aTK = ReadData<PlayerATK>(bytes, ref index);
        name = ReadString(bytes, ref index);
        return index - beginIndex;
    }

        Player player2 = new Player();
        player2.Reading(bytes);
        print(player2.lev);
        print(player2.aTK.atk);
        print(player2.name);

Guess you like

Origin blog.csdn.net/m0_51743362/article/details/124919237