Socket_区分消息类型四大类

58 阅读5分钟
(之前写的客户端服务端收发消息 只能接收和发送字符串类型 现在写的案例在之前基础上进行修改 可以接收和发送结构类对象数据)
创建了四个脚本
1.BaseData、PlayerData、baseMsg、PlayerMsg。
其中PlayerData和baseMsg继承BaseData基类,
PlayerMsg继承baseMsg基类。
BaseMsg是消息基类,
BaseData是数据读写基类,
PlayerData是用户结构类,
PlayerMsg玩家消息处理类。

一、BaseData基类 用于数据的序列化和反序列化 代码如下

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

public abstract class BaseData
{
    //获取子类字节数组容量大小
    public abstract int GetBytesNum();

    /// <summary>
    /// 把成员变量 序列化为 对应的字节数组
    /// </summary>
    /// <returns></returns>
    public abstract byte[] Writing();
    /// <summary>
    /// 把2进制字节数组 反序列化到 成员变量当中
    /// </summary>
    /// <param name="bytes">反序列化使用的字节数组</param>
    /// <param name="beginIndex">从多少索引开始解析</param>
    /// <returns></returns>
    public abstract int Reading(byte[] bytes,int beginIndex=0);

    /// <summary>
    /// 存储不同类型变量到指定的字节数组当中
    /// </summary>
    /// <param name="bytes">指定字节数组</param>
    /// <param name="value">具体的类型值</param>
    /// <param name="index">每次存储后用于记录当前索引位置的变量</param>
    protected void WriteInt(byte[] bytes, int value, ref int index)
    {
        BitConverter.GetBytes(value).CopyTo(bytes, index);
        index += sizeof(int);
    }
    protected void WriteFloat(byte[] bytes, float value, ref int index)
    {
        BitConverter.GetBytes(value).CopyTo(bytes, index);
        index += sizeof(float);
    }
    protected void WriteShort(byte[] bytes, short value, ref int index)
    {
        BitConverter.GetBytes(value).CopyTo(bytes, index);
        index += sizeof(short);
    }
    protected void WriteLong(byte[] bytes, long value, ref int index)
    {
        BitConverter.GetBytes(value).CopyTo(bytes, index);
        index += sizeof(long);
    }
    protected void WriteByte(byte[] bytes, byte value, ref int index)
    {
        bytes[index] = value;
        index += sizeof(byte);
    }
    protected void WriteBool(byte[] bytes, bool value, ref int index)
    {
        BitConverter.GetBytes(value).CopyTo(bytes, index);
        index += sizeof(bool);
    }
    protected void WriteString(byte[] bytes, string value, ref int index)
    {
        //先存储string字节数组的长度
        byte[] strBytes = Encoding.UTF8.GetBytes(value);
        /*BitConverter.GetBytes(strBytes.Length).CopyTo(bytes, index);
        index += sizeof(int);*/
        WriteInt(bytes, strBytes.Length, ref index);
        //再存储 string字节数组
        strBytes.CopyTo(bytes, index);
        index += strBytes.Length;
    }
    protected void writeData(byte[] bytes, BaseData data, ref int index)
    {
        data.Writing().CopyTo(bytes, index);
        index += data.GetBytesNum();
    }

    /// <summary>
    /// 读取不同类型变量到指定的字节数组当中
    /// </summary>
    /// <param name="bytes"></param>
    /// <param name="index"></param>
    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 long ReadLong(byte[] bytes,ref int index)
    {
        long value = BitConverter.ToInt64(bytes, index);
        index += sizeof(long);
        return value;
    }
    protected float ReadFloat(byte[] bytes,ref int index)
    {
        float value= BitConverter.ToSingle(bytes, index);
        index += sizeof(float);
        return value;
    }
    protected bool ReadBool(byte[] bytes, ref int index)
    {
        bool value=BitConverter.ToBoolean(bytes, index);
        index += sizeof(bool);
        return value;
    }
    protected byte ReadByte(byte[] bytes, ref int index)
    {
        byte value= bytes[index];
        index += sizeof(byte);
        return value;
    }

    protected string ReadString(byte[] bytes,ref int index)
    {
        //先读取长度
        int length=BitConverter.ToInt32(bytes, index);
        index += sizeof(int);
        string value = Encoding.UTF8.GetString(bytes, index, length);
        index += length;
        return value;
    }
    protected T ReadData<T>(byte[] bytes,ref int index) where T:BaseData,new()
    {
        T value = new T();
        index += value.Reading(bytes,index);
        return value;

    }
}

二、BaseMsg基类 继承BaseData 实现基类的抽象方法后,多加了一个虚方法,用于结构类添加自身消息ID

using System.Collections.Generic;
using UnityEngine;

public class BaseMsg : BaseData
{
    public override int GetBytesNum()
    {
        throw new System.NotImplementedException();
    }

    public override int Reading(byte[] bytes, int beginIndex = 0)
    {
        throw new System.NotImplementedException();
    }

    public override byte[] Writing()
    {
        throw new System.NotImplementedException();
    }

    //增加一个 添加自身ID的虚方法  谁需要用谁去重写
    public virtual int GetID()
    {
        return 0;
    }
}

玩家数据类PlayerData,继承BaseData 实现了抽象方法,也就是序列化和反序列化数据类消息

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


/// <summary>
/// 玩家数据类
/// </summary>
public class PlayerData : BaseData
{
    public string name;
    public int atk;
    public int lev;

    public override int GetBytesNum()
    {
        return 4+4+4+Encoding.UTF8.GetBytes(name).Length;  //拿到总长度
    }

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

    }

    public override byte[] Writing()
    {
        int index=0;
        byte[] bytes = new byte[GetBytesNum()];
        WriteString(bytes, name,ref index);
        WriteInt(bytes,atk,ref index);
        WriteInt(bytes,lev,ref index);
        return bytes;

    
    }
}

四、PlayerMsg 继承BaseMsg 实现了玩家信息的处理

1、首先重写BaseMsg的序列化和反序列化、获取字节数组长度以及自定义消息ID(进行ID判断去处理消息)
//假设有两个成员变量
1public int playerID;
2public PlayerData playerData;
//然后在序列化方法Writing()中去实现的是
int index=0; byte[] bytes = new byte[GetBytesNum()];  先实例化一个字节数组
//然后现将消息ID序列化到数组
WriteInt(bytes, GetID(), ref index); //先写入消息ID
//在写入玩家信息ID和playerData; 
WriteInt(bytes, playerID, ref index); 
writeData(bytes,playerData, ref index);
//返回字节数组
return bytes; Writing()方法体中的逻辑代码

接着就是反序列化方法Reading()中的功能
//只需要拿到玩家信息就行  消息ID在外部就序列化完成了 用于判断消息类型
int index=beginIndex; 
playerID = ReadInt(bytes, ref index); 
playerData=ReadData<PlayerData>(bytes, ref index); 
return index-beginIndex;  
//Reading方法内容完成

GetBytesNum(),获取字节数组长度方法
直接return返回出  4+ //消息ID的字节长度
                 4+ //玩家ID的字节长度
                 playerData.GetBytesNum().length; //PlayerData 的字节数组长度
/// <summary>
    /// 自定义的消息ID 用于区分是哪一个类
    /// </summary>
    /// <returns></returns>
    public override int GetID()
    {
    return 1001;
    }



代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 玩家消息脚本
/// </summary>
public class PlayerMsg : BaseMsg
{
    //玩家ID
    public int playerID;
    public PlayerData playerData;

    public override byte[] Writing()
    {
        int index=0;
        byte[] bytes = new byte[GetBytesNum()];
        WriteInt(bytes, GetID(), ref index); //先写入消息ID

        //再写入玩家信息
        WriteInt(bytes, playerID, ref index); 
        writeData(bytes,playerData, ref index);

        return bytes;
    }
    //读取 反序列化
    public override int Reading(byte[] bytes, int beginIndex = 0)
    {
        //读取数据的话 反序列化不需要去解析ID  再这反序列化之前就需要把ID反序列化出来
        //因为这样 才能判断到底需要用那个自定义类来反序列化
        int index=beginIndex;

        playerID = ReadInt(bytes, ref index);
        playerData=ReadData<PlayerData>(bytes, ref index);

        return index-beginIndex;

    }

    public override int GetBytesNum()
    {
    
        return 4 //第一个 4 是自定义的消息ID 的长度 
            +  4 //playerID 的字节数组长度
            +  playerData.GetBytesNum();  //PlayerData 的字节数组长度
    }
    /// <summary>
    /// 自定义的消息ID 用于区分是哪一个类
    /// </summary>
    /// <returns></returns>
    public override int GetID()
    {
    return 1001;
    }
}