小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Unity技術(shù)博客

 kiki的號(hào) 2017-07-22

Unity版本: 5.3

使用語(yǔ)言: C#


寫在前面

ProtoBuf是Google公司推出的一種二進(jìn)制序列化工具,適用于數(shù)據(jù)的網(wǎng)絡(luò)傳輸。
基于Socket實(shí)現(xiàn)時(shí)時(shí)通信,關(guān)于數(shù)據(jù)粘包的編碼和解碼處理是必不可少的。


實(shí)現(xiàn)功能:

   1.基于ProtoBuf序列化對(duì)象
   2.使用Socket實(shí)現(xiàn)時(shí)時(shí)通信
   3.數(shù)據(jù)包的編碼和解碼

3.數(shù)據(jù)包的編碼和解碼

首先,舉個(gè)例子,這個(gè)月信用卡被媳婦刷爆了,面對(duì)房貸車貸的壓力,我只能選擇分期付款。。。

那么OK了,現(xiàn)在我想問(wèn)一下,當(dāng)服務(wù)器向客戶端發(fā)送的數(shù)據(jù)過(guò)大時(shí)怎么辦呢?

當(dāng)服務(wù)器需要向客戶端發(fā)送一條很長(zhǎng)的數(shù)據(jù),也會(huì)“分期付款!”,服務(wù)器會(huì)把一條很長(zhǎng)的數(shù)據(jù)分成若干條小數(shù)據(jù),多次發(fā)送給客戶端。

可是,這樣就又有另外一個(gè)問(wèn)題,客戶端接受到多條數(shù)據(jù)之后如何解析?

這里其實(shí)就是客戶端的解碼。server發(fā)數(shù)據(jù)一般采用“長(zhǎng)度+內(nèi)容”的格式,Client接收到數(shù)據(jù)之后,先提取出長(zhǎng)度來(lái),然后根據(jù)長(zhǎng)度判斷內(nèi)容是否發(fā)送完畢。

再次重申,用戶在發(fā)送序列化好的消息的前,需要先編碼后再發(fā)送消息;用戶在接受消息后,需要解碼之后再解析數(shù)據(jù)(反序列化)。

using UnityEngine;
using System.Collections.Generic;
using System.IO;

/// <summary>
/// 編碼和解碼
/// </summary>
public class NetEncode {

    /// <summary>
    /// 將數(shù)據(jù)編碼 長(zhǎng)度+內(nèi)容
    /// </summary>
    /// <param name="data">內(nèi)容</param>
    public static byte[] Encode(byte[] data)
    {
        //整形占四個(gè)字節(jié),所以聲明一個(gè)+4的數(shù)組
        byte[] result = new byte[data.Length + 4];
        //使用流將編碼寫二進(jìn)制
        MemoryStream ms = new MemoryStream();
        BinaryWriter br = new BinaryWriter(ms);
        br.Write(data.Length);
        br.Write(data);
        //將流中的內(nèi)容復(fù)制到數(shù)組中
        System.Buffer.BlockCopy(ms.ToArray(), 0, result, 0, (int)ms.Length);
        br.Close();
        ms.Close();
        return result;
    }

    /// <summary>
    /// 將數(shù)據(jù)解碼
    /// </summary>
    /// <param name="cache">消息隊(duì)列</param>
    public static byte[] Decode(ref List<byte> cache)
    {
        //首先要獲取長(zhǎng)度,整形4個(gè)字節(jié),如果字節(jié)數(shù)不足4個(gè)字節(jié)
        if(cache.Count < 4)
        {
            return null;
        }
        //讀取數(shù)據(jù)
        MemoryStream ms = new MemoryStream(cache.ToArray());
        BinaryReader br = new BinaryReader(ms);
        int len = br.ReadInt32();
        //根據(jù)長(zhǎng)度,判斷內(nèi)容是否傳遞完畢
        if(len > ms.Length - ms.Position)
        {
            return null;
        }
        //獲取數(shù)據(jù)
        byte[] result = br.ReadBytes(len);
        //清空消息池
        cache.Clear();
        //講剩余沒(méi)處理的消息存入消息池
        cache.AddRange(br.ReadBytes((int)ms.Length - (int)ms.Position));

        return result;
    }
}

用戶接受數(shù)據(jù)代碼如下:

using System;
using System.Collections.Generic;
using System.Net.Sockets;

/// <summary>
/// 表示一個(gè)客戶端
/// </summary>
public class NetUserToken {
    //連接客戶端的Socket
    public Socket socket;
    //用于存放接收數(shù)據(jù)
    public byte[] buffer;
    //每次接受和發(fā)送數(shù)據(jù)的大小
    private const int size = 1024;

    //接收數(shù)據(jù)池
    private List<byte> receiveCache;
    private bool isReceiving;
    //發(fā)送數(shù)據(jù)池
    private Queue<byte[]> sendCache;
    private bool isSending;

    //接收到消息之后的回調(diào)
    public Action<NetModel> receiveCallBack;


    public NetUserToken()
    {
        buffer = new byte[size];
        receiveCache = new List<byte>();
        sendCache = new Queue<byte[]>();
    }

    /// <summary>
    /// 服務(wù)器接受客戶端發(fā)送的消息
    /// </summary>
    /// <param name="data">Data.</param>
    public void Receive(byte[] data)
    {
        UnityEngine.Debug.Log("接收到數(shù)據(jù)");
        //將接收到的數(shù)據(jù)放入數(shù)據(jù)池中
        receiveCache.AddRange(data);
        //如果沒(méi)在讀數(shù)據(jù)
        if(!isReceiving)
        {
            isReceiving = true;
            ReadData();
        }
    }

    /// <summary>
    /// 讀取數(shù)據(jù)
    /// </summary>
    private void ReadData()
    {
        byte[] data = NetEncode.Decode(ref receiveCache);
        //說(shuō)明數(shù)據(jù)保存成功
        if(data != null)
        {
            NetModel item = NetSerilizer.DeSerialize(data);
            UnityEngine.Debug.Log(item.Message);
            if(receiveCallBack != null)
            {
                receiveCallBack(item);
            }
            //尾遞歸,繼續(xù)讀取數(shù)據(jù)
            ReadData();
        }
        else
        {
            isReceiving = false;
        }
    }

    /// <summary>
    /// 服務(wù)器發(fā)送消息給客戶端
    /// </summary>
    public void Send()
    {
        try {
            if (sendCache.Count == 0) {
                isSending = false;
                return;    
            }
            byte[] data = sendCache.Dequeue ();
            int count = data.Length / size;
            int len = size;
            for (int i = 0; i < count + 1; i++) {
                if (i == count) {
                    len = data.Length - i * size;
                }
                socket.Send (data, i * size, len, SocketFlags.None);
            }
            UnityEngine.Debug.Log("發(fā)送成功!");
            Send ();
        } catch (Exception ex) {
            UnityEngine.Debug.Log(ex.ToString());
        }
    }

    public void WriteSendDate(byte[] data){
        sendCache.Enqueue(data);
        if(!isSending)
        {
            isSending = true;
            Send();
        }
    }
}

寫在最后

 #成功的道路沒(méi)有捷徑,代碼這條路更是如此,唯有敲才是王道。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約