Unity游戏开发 基于多线程的Http网络框架完整篇

这篇主要是提供完整的代码。。。注释较少请见谅,如果对流程有疑惑可以参考**《Unity游戏开发 基于多线程的Http网络框架基础篇》

完整篇除了基础篇讲到的内容之外,出于对性能和安全性的考虑还覆盖了如下内容:

单例:(BaseController

       **关于单例请参考《Unity游戏开发 单例基类》

对象池: (PoolablePoolManager

加密:(Encry

这些内容后续有时间写的话会把链接放上来,目前把所有代码贴出来主要是方便直接拷贝就可以使用了。

在更完整的版本里还有一个事件分发的处理,后续如果有时间写UI框架的话会把这块关联起来。

目录

使用示例

HttpManager(http管理器)

HttpClient(http核心逻辑)

HttpPack(http数据包)

BlockQueue(多线程队列)

Encry(加密)

BaseController(单例)

Poolable(对象池之可缓存对象)

PoolManager(对象池管理器)



使用示例

void Start()
{
    // 发起请求
    HttpManager.instance.HttpPost(1, "http://es.dota2.uuu9.com/players", false);
}

int id = 0; int code = 0; string data = "";
void Update()
{
    // 从接受队列取得消息(此处本来是和lua的http模块以及ui框架结合做错误码处理以及网络事件分发的)
    if(HttpManager.instance.TryGetResPonse(ref id, ref code, ref data))
    {
        UnityEngine.Debug.LogError(data);
    }
}

这里加密传了false,如果传入true的话会将返回的消息用Encry模块去解密。

这个需要服务器的配合,两边约定好加密的密钥。

目前只是对接收到的数据进行了解密处理,如果有需要的话也可以和服务器做协商,在发送的json参数中用某个字段将实际游戏中用到的参数通过Encry加密后保存起来发送给服务器,服务器解密后再做处理。

HttpManager(http管理器)

using System.Text;

public enum HttpType
{
    Get,
    Post,
}

public class HttpManager : BaseController
{
    private HttpClient _httpClient = new HttpClient();
    private StringBuilder _getBuilder = new StringBuilder();

    public void HttpGet(int key, string url, bool encry, string param = null)
    {
        _getBuilder.Clear();
        _getBuilder.Append(url);
        if (param != null)
        {
            _getBuilder.Append("?");
            _getBuilder.Append(param);
        }
        _httpClient.AddHttpReq(key, HttpType.Get, _getBuilder.ToString(), encry);
    }

    public void HttpPost(int key, string url, bool encry, string param = null)
    {
        _getBuilder.Clear();
        _getBuilder.Append(url);
        _httpClient.AddHttpReq(key, HttpType.Post, _getBuilder.ToString(), encry, param);
    }

    public bool TryGetResPonse(ref int key, ref int code, ref string data)
    {
        HttpPack pack;
        if (_httpClient.TryGetResponse(out pack))
        {
            key = pack.key;
            code = pack.code;
            data = pack.response;
            pack.Dispose();
            return true;
        }
        return false;
    }
}

HttpClient(http核心逻辑)

using System.Net;
using System.Text;
using System.IO;
using System.Threading;
using System;

public class HttpClient
{
    private Encry _encry = new Encry("testkey");
    private Thread _sendTask;

    private BlockQueue _sendList = new BlockQueue(10);
    private BlockQueue _receiveList = new BlockQueue(10);

    #region 外部接口
    public bool TryGetResponse(out HttpPack pack)
    {
        if (_receiveList.count > 0)
        {
            pack = _receiveList.Dequeue();
            return true;
        }
        else
        {
            pack = null;
            return false;
        }
    }

    public void AddHttpReq(int key, HttpType type, string url, bool encry, string param = null)
    {
        HttpPack pack = HttpPack.GetPooled();
        pack.key = key;
        pack.type = type;
        pack.url = url;
        pack.param = param;
        pack.encry = encry;
        pack.tryNum = 3;
        _sendList.Enqueue(pack);
    }
    #endregion

    public HttpClient()
    {
        _sendTask = StartDaemonThread(StartSend);
    }

    private static Thread StartDaemonThread(ThreadStart threadMethod)
    {
        Thread thread = new Thread(threadMethod);
        thread.IsBackground = true;
        thread.Start();
        return thread;
    }

    private void StartSend()
    {
        while (true)
        {
            HandleSend();
        }
    }

    private void HandleSend()
    {
        if (_sendList.count > 0)
        {
            HttpPack pack = _sendList.Dequeue();
            switch (pack.type)
            {
                case HttpType.Get:
                    {
                        Get(ref pack, pack.url, pack.encry);
                        HandleRecive(ref pack);
                        return;
                    }
                case HttpType.Post:
                    {
                        Post(ref pack, pack.url, pack.param, pack.encry);
                        HandleRecive(ref pack);
                        return;
                    }
            }
        }
    }

    // 处理接收
    private void HandleRecive(ref HttpPack pack)
    {
        // 异常时重试
        if (pack.code != 200 && pack.tryNum > 0)
        {
            pack.tryNum--;
            _sendList.Enqueue(pack);
        }
        else
        {
            _receiveList.Enqueue(pack);
        }
    }

    private void Get(ref HttpPack pack, string url, bool encry, int timeout = 2000, Encoding encode = null)
    {
        HttpWebRequest req = null;
        HttpWebResponse res = null;
        req = (HttpWebRequest)WebRequest.Create(url);
        req.AllowAutoRedirect = false;
        req.Timeout = timeout;

        try
        {
            res = (HttpWebResponse)req.GetResponse();
        }
        catch (WebException ex)
        {
            res = (HttpWebResponse)ex.Response;
        }

        pack.code = ((int)res.StatusCode);
        using (Stream stream = res.GetResponseStream())
        {
            pack.response = GetStrResponse(stream, encry, encode);
        }

        res.Close();
        req.Abort();
    }

    private void Post(ref HttpPack pack, string url, string postdata, bool encry, int timeout = 2000, Encoding encode = null)
    {
        HttpWebRequest req;
        HttpWebResponse res;
        encode = encode ?? Encoding.UTF8;
        req = (HttpWebRequest)WebRequest.Create(new Uri(url));
        req.Method = "POST";
        req.Timeout = timeout;

        if (postdata != null)
        {
            byte[] byteArray = encode.GetBytes(postdata);
            Stream stream = req.GetRequestStream();
            stream.Write(byteArray, 0, byteArray.Length);
            stream.Close();
        }

        try
        {
            res = (HttpWebResponse)req.GetResponse();
            pack.code = (int)res.StatusCode;
            using (Stream resStream = res.GetResponseStream())
            {
                pack.response = GetStrResponse(resStream, encry, encode);
            }
            res.Close();
        }
        catch (WebException ex)
        {
            pack.code = (int)ex.Status;
        }

        req.Abort();
    }

    // 处理加密
    private string GetStrResponse(Stream stream, bool encry, Encoding encode)
    {
        using (StreamReader reader = new StreamReader(stream))
        {
            string str = reader.ReadToEnd();
            if (encry)
            {
                byte[] unEncryBytes = encode.GetBytes(str);
                _encry.DoEncry(unEncryBytes);
                return encode.GetString(unEncryBytes);
            }
            else
            {
                return str;
            }
        }
    }
}

HttpPack(http数据包)

public class HttpPack : Poolable
{
    public HttpType type;
    public int code;
    public bool encry;
    public int tryNum;
    public int key;
    public string url;
    public string param;
    public string response;
}

BlockQueue(多线程队列)

using System;
using System.Collections.Generic;
using System.Threading;

public class BlockQueue
{
    private readonly Queue _queue;
    private readonly int _capacity;
    private bool _closing;

    public int count
    {
        get { return _queue.Count; }
    }

    public BlockQueue(int capacity)
    {
        this._capacity = capacity;
        this._queue = new Queue(capacity);
    }

    public void Enqueue(T item)
    {
        lock (_queue)
        {
            while (_queue.Count >= _capacity)
            {
                Monitor.Wait(_queue);
            }
            _queue.Enqueue(item);
            if (_queue.Count == 1)
            {
                Monitor.PulseAll(_queue);
            }
        }
    }

    public T Dequeue()
    {
        lock (_queue)
        {
            while (_queue.Count == 0)
            {
                Monitor.Wait(_queue);
            }
            T item = _queue.Dequeue();
            if (_queue.Count == _capacity - 1)
            {
                Monitor.PulseAll(_queue);
            }
            return item;
        }
    }


    public void Close()
    {
        lock (_queue)
        {
            _closing = true;
            Monitor.PulseAll(_queue);
        }
    }

    public bool TryDequeue(out T value)
    {
        lock (_queue)
        {
            while (_queue.Count == 0)
            {
                if (_closing)
                {
                    value = default(T);
                    return false;
                }
                Monitor.Wait(_queue);
            }
            value = _queue.Dequeue();
            if (_queue.Count == _capacity - 1)
            {
                Monitor.PulseAll(_queue);
            }
            return true;
        }
    }
}

Encry(加密)

public class Encry
{
    private string _encryKey;

    public Encry(string encryKey)
    {
        _encryKey = encryKey;
    }

    public void DoEncry(byte[] data)
    {
        int keyId = 0;
        for (int i = 0; i < data.Length; i++)
        {
            data[i] ^= (byte)_encryKey[keyId];
            keyId++;
            if (keyId >= _encryKey.Length)
            {
                keyId = 0;
            }
        }
    }
}

BaseController(单例)

using UnityEngine;

public abstract class BaseController : MonoBehaviour 
    where T : BaseController
{
    private const string ROOT_NAME = "SingleRoot";
    private static T _instance = null;

    private static GameObject root
    {
        get
        {
            GameObject singleRoot = GameObject.Find(ROOT_NAME);
            if (singleRoot == null)
            {
                singleRoot = new GameObject(ROOT_NAME);
                DontDestroyOnLoad(singleRoot);
            }
            return singleRoot;
        }
    }

    public static T instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject gameObject = new GameObject(typeof(T).Name);
                gameObject.transform.SetParent(root.transform);
                _instance = gameObject.AddComponent();
            }
            return _instance;
        }
    }

    public virtual void Init()
    {
        
    }

    public virtual void Remove()
    {
        if (_instance == this)
            _instance = null;

        GameObject.Destroy(gameObject);
    }
}

Poolable(对象池之可缓存对象)

using System;
using System.Collections.Generic;

public class Poolable where T : Poolable
{
    private static Queue _pool;
    private static Queue Pool
    {
        get
        {
            if (_pool == null)
            {
                _pool = new Queue();
                PoolManager.instance.RegisterPool(ClearPool);
            }
            return _pool;
        }
    }

    public static T GetPooled()
    {
        T output;
        if (Pool.Count == 0)
        {
            output = Activator.CreateInstance();
        }
        else
        {
            output = _pool.Dequeue();
        }
        return output;
    }

    public static void ClearPool()
    {
        _pool.Clear();
    }

    public void Dispose()
    {
        OnDispose();
        Pool.Enqueue((T)this);
    }

    protected virtual void OnDispose()
    {

    }
}

PoolManager(对象池管理器)

using System;
using System.Collections;
using System.Collections.Generic;

class PoolManager : BaseController
{
    public delegate void PoolClearHandler();
    private event PoolClearHandler _onFlush;

    public PoolManager()
    {

    }

    public void RegisterPool(PoolClearHandler clearHandler)
    {
        _onFlush += clearHandler;
    }

    public void Flush()
    {
        _onFlush?.Invoke();
    }
}

你可能感兴趣的:(unity,游戏开发,unity,游戏,c#,http)