Unity中使用Socket进行Tcp连接-发送协议粘包/发送队列(四)

上一篇文章里介绍,在接收协议时会出现粘包情况,同样的,在协议发送时也会出现此问题。

前面的文章介绍发送协议和接收协议的时候都是从字符串直接转换为byte数组,这在发送协议和解析协议时都不规范。

public class MsgBase {

    public string protoName = "";

    public static byte[] Encode(MsgBase msg)
    {
        string sendStr = JsonUtility.ToJson(msg);
        sendStr = msg.protoName + "|"+ sendStr;
        return System.Text.Encoding.Default.GetBytes(sendStr);
    }
    public static MsgBase Decode(string sendStr)
    {
        string[] split = sendStr.Split('|');
        string msgName = split[0];
        string msgBody = split[1];
        MsgBase msgBase = (MsgBase)JsonUtility.FromJson(msgBody, Type.GetType(msgName));
        return msgBase;
    }
}
public class MsgHeartbeat : MsgBase
{
    public MsgHeartbeat()
    {
        protoName = "MsgHeartbeat";
    }
}
public class MsgRotate : MsgBase
{
    public MsgRotate()
    {
        protoName = "MsgRotate";
    }
    public Vector2 speed;
}

按照上述方式,定义协议基类MsgBase,在其中定义协议名和协议体,Encode代表发送协议前的协议编码,Decode为接收到协议后的解码。

定义ByteArray记录发送位置

public class ByteArray
{
    public byte[] bytes;
    public int readIndex;
    private int writeIndex;
    public int length { get { return writeIndex - readIndex; } }

    public ByteArray(byte[] defaultByte)
    {
        bytes = defaultByte;
        readIndex = 0;
        writeIndex = defaultByte.Length;
    }
}

异步发送协议,从队列中取出一条发送,单条没有全部发送成功,则在新的数据位置继续发送 

 public static void Send(MsgBase msg)
    {
        if (socket == null) return;
        if (!socket.Connected) return;

        byte[] bodyBytes = MsgBase.Encode(msg);//协议编码
        Int16 bodyLenth = (Int16)bodyBytes.Length;//计算协议长度
        byte[] lengthByte = BitConverter.GetBytes(bodyLenth);//将协议长度信息转换为字节数组

        if (!BitConverter.IsLittleEndian)//判断大小端
        {
            Debug.Log("Reverse lengthByte");
            lengthByte.Reverse();
        }
        byte[] sendBytes = lengthByte.Concat(bodyBytes).ToArray();//将协议长度信息和协议信息拼接在一起,其中协议长度信息占两个字节

        ByteArray ba = new ByteArray(sendBytes);
        lock (writeQueue)
        {
            writeQueue.Enqueue(ba);
        }
        if (writeQueue.Count == 1)
        {
            socket.BeginSend(sendBytes, 0, sendBytes.Length, 0, SendCallBack, socket);
        }
    }
    private static void SendCallBack(IAsyncResult result)//异步发送协议回调
    {
        Socket socket = (Socket)result.AsyncState;
        int count=socket.EndSend(result);
        ByteArray ba;
        lock (writeQueue)
        {
            ba = writeQueue.First();
        }
        ba.readIndex += count;//记录发送数量
        if (ba.length==0)//发送完成则取下一条
        {
            writeQueue.Dequeue();
            ba = writeQueue.First();
        }
        if (ba != null)//没发送完成则记录发送
        {
            socket.BeginSend(ba.bytes,ba.readIndex,ba.length,0,SendCallBack,socket);
        }
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值