Unity网络开发记录(五):二进制传输消息类

15 篇文章 0 订阅

消息类

前篇所写的CS模型只能传输字符串,在本篇文章中,尝试在服务端一次传输多种类型的数据,并在客户端接收到信息之后进行解析显示

为了实现对不同类型的数据传输,需要将不同类型的数据都转换成二进制的形式在网络中进行传输。所以要实现一个消息基类,提供各种类型数据的序列化与反序列化方法,再让需要发送的数据类继承该基类,实现其中信息的序列化等操作

using System;
using System.Text;

public abstract class BaseData 
{
    /// <summary>
    /// 获取字节数
    /// </summary>
    /// <returns></returns>
    public abstract int GetByteNum();

    /// <summary>
    /// 写入
    /// </summary>
    /// <returns></returns>
    public abstract byte[] Writing();

    /// <summary>
    /// 读取
    /// </summary>
    /// <param name="bytes"></param>
    /// <param name="index"></param>
    /// <returns></returns>
    public abstract int Reading(byte[] bytes, int index = 0);

    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 WriteString(byte[] bytes, string value, ref int index)
    {
        byte[] b1 = Encoding.UTF8.GetBytes(value);
        BitConverter.GetBytes(b1.Length).CopyTo(bytes, index);
        index += sizeof(int);
        b1.CopyTo(bytes, index);
        index += b1.Length;
    }

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

    protected void WriteData(byte[] bytes, BaseData data, ref int index)
    {
        data.Writing().CopyTo(bytes, index);
        index += data.GetByteNum();
    }

    protected int ReadInt(byte[] bytes, ref int index)
    {
        int v = BitConverter.ToInt32(bytes, index);
        index += sizeof(int);
        return v;
    }
    protected string ReadString(byte[] bytes, ref int index)
    {
        int num = BitConverter.ToInt32(bytes, index);
        index += sizeof(int);
        string v = Encoding.UTF8.GetString(bytes, index, num);
        index += num;
        return v;
    }

    protected float ReadFloat(byte[] bytes, ref int index)
    {
        float v = BitConverter.ToSingle(bytes, index);
        index += sizeof(float);
        return v;
    }

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

    protected T ReadData<T>(byte[] bytes, ref int index) where T : BaseData, new()
    {
        T data = new T();
        index += data.Reading(bytes, index);
        return data;
    }
}

创建一个数据类,继承自消息基类,实现一下写入和读取的方法



using System;
using System.Text;

public class PlayerData : BaseData
{
    public int atk;
    public bool sex;
    public string name;

    public override int GetByteNum()
    {
        //int bool int(string转换成字节数组后的字节数) 字符串转字符数组后的长度 总共所占的字节数
        return sizeof(int) + sizeof(bool) + sizeof(int) + Encoding.UTF8.GetBytes(name).Length;
    }

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

    public override byte[] Writing()
    {
        int index = 0;
        byte[] bytes = new byte[GetByteNum()];
        WriteInt(bytes, atk, ref index);
        WriteBool(bytes, sex, ref index);
        WriteString(bytes, name, ref index);
        return bytes;
    }
}

为了区别不同的消息类型,需要添加一个消息头,其中有标识类型的ID

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

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

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

    public virtual int GetID()
    {
        return 0;//默认id为0
    }
}

 

创建一个最终的玩家信息类,实现读取写入方法,并设置一个标识id



public class PlayerMsg : BaseMsg
{
    public int playerID;
    public PlayerData data;

    public override int GetByteNum()
    {
        //消息头长度,int,PlayerData
        return sizeof(int) + sizeof(int) + data.GetByteNum();
    }

    public override int Reading(byte[] bytes, int index = 0)
    {
        int _index = index;
        playerID = ReadInt(bytes, ref _index);
        data = ReadData<PlayerData>(bytes, ref _index);
        return _index - index;
    }

    public override byte[] Writing()
    {
        int index = 0;
        byte[] bytes = new byte[GetByteNum()];
        WriteInt(bytes, GetID(), ref index);
        WriteInt(bytes, playerID, ref index);
        WriteData(bytes, data, ref index);
        return bytes;
    }

    public override int GetID()
    {
        return 10086;
    }

}

使用例

在服务端调用Writing方法进行序列化,然后Send。在客户端Receive后调用Reading进行反序列化

        public void Send(string info)
        {
            if (socket != null)
            {
                try
                {
                    //socket.Send(Encoding.UTF8.GetBytes(info));

                    PlayerMsg msg = new PlayerMsg();
                    msg.playerID = 114;
                    msg.data = new PlayerData();
                    msg.data.name = "123";
                    msg.data.atk = 122;
                    msg.data.sex = true;

                    socket.Send(msg.Writing());

                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);   
                }
            }
        }

先解析消息头,获得消息类型,然后根据类型进行对应解析 

    private void ReceiveMsg(object obj)
    {
        if (socket is null) return;

        while(isConnteced)
        {
            if (socket.Available > 0)
            {
                num = socket.Receive(reveiveBuffer);
                int id = BitConverter.ToInt32(reveiveBuffer, 0);
                switch (id)
                {
                    case 10086:
                        PlayerMsg msg = new PlayerMsg();
                        msg.Reading(reveiveBuffer, 4);
                        print(msg.playerID);
                        print(msg.data.atk);
                        print(msg.data.name);
                        print(msg.data.sex);
                        break;
                    default:
                        break;
                }


                //receiveQue.Enqueue(Encoding.UTF8.GetString(reveiveBuffer, 0, num));
            }
        }
    }

先启动服务端,然后在unity中运行客户端,可以看到信息解析成功了

实现了最基本的序列化反序列化通信信息的操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值