Common(七)—— NetworkManager

目录为:Assets/Scripts/Common/目录下,
NetworkManger.cs
当然看名字就知道啥意思了.

下面的代码里我注释了一些,以便可以在下一篇文章单独测试一下.

这里面最重要的就是Init方法,Update方法,SendMsg方法,
因为这三个方法是在外面要用的。

下一篇测试一下.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Net;
//using ProtoBuf;
using System.Net.Sockets;
using System.Threading;

//继承单例
public class NetworkManager: Singleton
{
    //Server type
    public enum ServerType
    {
        GateServer = 0,
        BalanceServer,
        LoginServer
    }

    //client
    private TcpClient m_Client = null;
    private TcpClient m_Connecting = null;

    //服务器IP
    private string m_IP = "127.0.0.1";
    //端口号
    private Int32 m_Port = 40001;

    private Int32 m_n32ConnectTimes = 0;
    //Server Type
    private ServerType serverType = ServerType.BalanceServer;
    private float m_CanConnectTime = 0f;
    //超时
    private float m_RecvOverTime = 0f;
    private float mRecvOverDelayTime = 2f;
    private Int32 m_ConnectOverCount = 0;
    private float m_ConnectOverTime = 0f;
    private Int32 m_RecvOverCount = 0;
    private bool canReconnect =false;

    //这里和CMemBuffer有点像
    //m_RecvBuffer:第一个四字节:length,length包括了length和type所占用的8个字节
    //m_RecvBuffer:第二个四字节:type
    //m_RecvBuffer:再后面就是data了
    public byte[] m_RecvBuffer = new byte[2 * 1024 * 1024];
    public Int32 m_RecvPos = 0;

    //Error时会赋值成null
    IAsyncResult mRecvResult;

    IAsyncResult mConnectResult;

    //发送数据stream
    public System.IO.MemoryStream mSendStream = new System.IO.MemoryStream ();

    //MsgIds
    public List<int> mReceiveMsgIDs = new List<int> ();

    //接收数据stream
    public List mReceiveStreams = new List ();

    //MemoryStream pool
    public List mReceiveStreamsPool = new List ();

    //构造函数
    public NetworkManager()
    {
        //pool里放50个MemoryStream
        for (int i = 0; i < 50; i++)
        {
            mReceiveStreamsPool.Add (new System.IO.MemoryStream ());
        }

        /*
        //下面全是用工具生成的

        //预先创建消息RuntimeTypeModel运行时类型模型
        //A
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        //B
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        //C
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        //D
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        //E
        ProtoBuf.Serializer.PrepareSerializer();
        //F
        ProtoBuf.Serializer.PrepareSerializer();
        //G
        ProtoBuf.Serializer.PrepareSerializer();
        //H
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        //L
        ProtoBuf.Serializer.PrepareSerializer();
        //M
        ProtoBuf.Serializer.PrepareSerializer();
        //N
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        //P
        ProtoBuf.Serializer.PrepareSerializer();
        //S
        ProtoBuf.Serializer.PrepareSerializer();
        //R
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        ProtoBuf.Serializer.PrepareSerializer();
        //U
        ProtoBuf.Serializer.PrepareSerializer();

        */
    }

    //析构函数
    ~NetworkManager()
    {
        //接收stream
        foreach (System.IO.MemoryStream one in mReceiveStreams)
        {
            one.Close ();
        }

        //MemoryStream池释放掉
        foreach(System.IO.MemoryStream one in mReceiveStreamsPool)
        {
            one.Close ();
        }

        //发送stream
        if (mSendStream != null)
        {
            mSendStream.Close ();
        }

        //client
        if (m_Client != null)
        {
            m_Client.Client.Shutdown (SocketShutdown.Both);
            //NetworkStream关闭
            m_Client.GetStream ().Close ();
            //TcpClient
            m_Client.Close ();
            m_Client = null;
        }
    }

    public void Init(string ip, Int32 port, ServerType type)
    {
        Debug.Log ("set network ip:" + ip + " port:" + port + "type" + type);
        m_IP = ip;
        m_Port = port;
        serverType = type;
        m_n32ConnectTimes = 0;
        canReconnect = true;
        m_RecvPos = 0;

        #if UNITY_EDITOR
        mRecvOverDelayTime = 20000f;
        #endif
    }

    public void UnInit ()
    {
        canReconnect = false;
    }

    //连接
    public void Connect ()
    {
        if (!canReconnect)
        {
            return;
        }

        //mCanConnectTime = 0.0f
        if (m_CanConnectTime > Time.time)
        {
            return;
        }

        if (m_Client != null)
        {
            throw new Exception("fuck, The socket is connecting, can not connect again!");
        }

        if (m_Connecting != null)
        {
            throw new Exception ("fuckm The socket is connecting, can not connect again!");
        }

        Debug.Log ("IClientSession Connect");

        //ip
        IPAddress ipAddress = IPAddress.Parse (m_IP);

        try
        {
            m_Connecting = new TcpClient();

            //开始对一个远程主机连接的异步请求。远程主机由IPAddress和端口号(Int32)指定
            mConnectResult = m_Connecting.BeginConnect(m_IP, m_Port, null, null);

            m_ConnectOverCount = 0;

            m_ConnectOverTime = Time.time + 2;
        }
        catch (Exception exc)
        {
            Debug.Log (exc.ToString ());

            m_Client = m_Connecting;

            m_Connecting = null;

            mConnectResult = null;

            OnConnectError (m_Client, null);
        }
    }

    //关闭
    public void Close()
    {
        if (m_Client != null)
        {
            OnClosed (m_Client, null);
        }
    }

    public void Update(float fDeltaTime)
    {
        if (m_Client != null)
        {
            //Msg操作
            DealWithMsg ();

            if (mRecvResult != null)
            {
                //接收超时
                if (m_RecvOverCount > 200 && Time.time > m_RecvOverTime)
                {
                    Debug.LogError ("recv data over 200, so close network!");
                    Close ();
                    return;
                }

                ++m_RecvOverCount;

                //获取一个值,该值指示异步操作是否已完成。
                //当此属性是true, 你可以假定为安全地放弃用于分配由异步操作的任何资源.
                if (mRecvResult.IsCompleted)
                {
                    //-------------------------------------------------------
                    try
                    {
                        //EndRead:处理异步读取的结束
                        //返回读取的字节数量
                        Int32 n32BytesRead = m_Client.GetStream().EndRead(mRecvResult);
                        m_RecvPos += n32BytesRead;

                        if (n32BytesRead == 0)
                        {
                            Debug.LogError("cannot recv data now, so close network 2");
                            Close();
                            return;
                        }
                    }
                    catch (Exception exc)
                    {
                        Debug.LogError (exc.ToString ());
                        Close ();
                        return;
                    }

                    OnDataReceived (null, null);

                    //-------------------------------------------------------

                    if (m_Client != null)
                    {
                        try
                        {
                            mRecvResult = m_Client.GetStream().BeginRead(m_RecvBuffer, m_RecvPos, m_RecvBuffer.Length - m_RecvPos, null, null);
                            m_RecvOverTime = Time.time + mRecvOverDelayTime;
                            m_RecvOverCount = 0;
                        }
                        catch (Exception exc)
                        {
                            Debug.LogError (exc.ToString ());
                            Close ();
                            return;
                        }
                    }
                }
            }

            if (m_Client != null && m_Client.Connected == false)
            {
                Debug.LogError ("client is close by system, so close it now.");
                Close ();
                return;
            }
        }
        //m_RecvResult == null时
        else if (m_Connecting != null)
        {
            if (m_ConnectOverCount > 200 && Time.time > m_ConnectOverTime)
            {
                Debug.LogError ("cant connect, so close network.");

                m_Client = m_Connecting;

                m_Connecting = null;

                mConnectResult = null;

                OnConnectError (m_Client, null);

                return;
            }

            ++m_ConnectOverCount;

            if (mConnectResult.IsCompleted)
            {
                m_Client = m_Connecting;

                m_Connecting = null;

                mConnectResult = null;

                if (m_Client.Connected)
                {
                    try
                    {
                        m_Client.NoDelay = true;

                        m_Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 2000);

                        m_Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 2000);

                        m_Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

                        //从0开始填m_RecvBuffer
                        mRecvResult = m_Client.GetStream().BeginRead(m_RecvBuffer, 0, m_RecvBuffer.Length, null, null);

                        //每次加2毫秒
                        m_RecvOverTime = Time.time + mRecvOverDelayTime;

                        m_RecvOverCount = 0;

                        OnConneted(m_Client, null);
                    }
                    catch (Exception exc)
                    {
                        Debug.LogError (exc.ToString ());
                        Close ();
                        return;
                    }
                }
                else
                {
                    OnConnectError (m_Client, null);
                }
            }
        }
        else
        {
            //这里重新连接
            Connect ();
        }
    }

    //发送数据
    //ProtoBuf
    public void SendMsg(/*ProtoBuf.IExtensible pMsg, Int32 n32MsgID*/ byte[] bytes, int bytesLength)
    {
        if (m_Client != null)
        {
            //这个mSendStream反复使用
            //清除stream
            mSendStream.SetLength (0);
            mSendStream.Position = 0;

            //序列到stream
            //ProtoBuf.Serializer.Serialize (mSendStream, pMsg);
            //CMsg pcMsg = new CMsg ((int)mSendStream.Length);
            //pcMsg.setProtocalID (n32MsgId);
            //数据写进pcMsg
            //pcMsg.Add (mSendStream.ToArray (), 0, (int)mSendStream.Length);

            #if UNITY_EDITOR
            #else
            try
            {
#endif

#if LOG_FILE && UNITY_EDITOR

                if (n32MsgID != 8192 && n32MsgID != 16385)
                {
                    string msgName = "";
                    if (Enum.IsDefined(typeof(GCToBS.MsgNum), n32MsgID))
                    {
                    msgName = ((GCToBS.MsgNum)n32MsgID).ToString();
                    }
                    else if (Enum.IsDefined(typeof(GCToCS.MsgNum), n32MsgID))
                    {
                    msgName = ((GCToCS.MsgNum)n32MsgID).ToString();
                    }
                    else if (Enum.IsDefined(typeof(GCToLS.MsgID), n32MsgID))
                    {
                    msgName = ((GCToLS.MsgID)n32MsgID).ToString();
                    }
                    else if (Enum.IsDefined(typeof(GCToSS.MsgNum), n32MsgID))
                    {
                    msgName = ((GCToSS.MsgNum)n32MsgID).ToString();
                    }

                    using (System.IO.StreamWriter sw = new System.IO.StreamWriter(@"E:\Log.txt", true))
                    {
                    sw.WriteLine(Time.time + "   发送消息:\t" + n32MsgID + "\t" + msgName);
                    }
                }

#endif

                //把pcMsg写进NetworkStream
                //写进去,然后就会发送
                //m_Client.GetStream().Write(pcMsg.GetMsgBuffer(), 0, (int)pcMsg.GetMsgSize());
                m_Client.GetStream().Write(bytes, 0, bytesLength);
#if UNITY_EDITOR

#else
            }
            catch (Exception exc)
            {
                Debug.logError(exc.ToString());
                Close();
            }
#endif

        }
    }

    public void OnConneted(object sender, EventArgs e)
    {
        switch (serverType)
        {
        case ServerType.BalanceServer:
            {
                //CGLCtrl_GameLogic.Instance.BsOneClientLogin ();
            }
            break;

        case ServerType.GateServer:
            {
                ++m_n32ConnectTimes;
                if (m_n32ConnectTimes > 1) {
                    //CGLCtrl_GameLogic.Instance.EmsgTocsAskReconnect ();
                } else {
                    //CGLCtrl_GameLogic.Instance.GameLogin ();
                }
                EventCenter.Broadcast (EGameEvent.eGameEvent_ConnectServerSuccess);
            }
            break;

        case ServerType.LoginServer:
            {
                //这里面会有发送msg信息的操作
                //CGLCtrl_GameLogic.Instance.EmsgToLs_AskLogin ();
            }
            break;

        }
    }

    //连接错误
    public void OnConnectError(object sender, ErrorEventArgs e)
    {
        Debug.Log ("OnConnectError begin");

        try
        {
            m_Client.Client.Shutdown(SocketShutdown.Both);
            m_Client.GetStream().Close();
            m_Client.Close();
            m_Client = null;
        }
        catch (Exception exc)
        {
            Debug.Log (exc.ToString ());
        }

        mRecvResult = null;
        m_Client = null;
        m_RecvPos = 0;
        m_RecvOverCount = 0;
        m_ConnectOverCount = 0;

        EventCenter.Broadcast (EGameEvent.eGameEvent_ConnectServerFail);

        Debug.Log ("OnConnectError end");
    }

    public void OnClosed(object sender, EventArgs e)
    {
        EventCenter.Broadcast (EGameEvent.eGameEvent_ConnectServerFail);

        try
        {
            m_Client.Client.Shutdown(SocketShutdown.Both);
            m_Client.GetStream().Close();
            m_Client.Close();
            m_Client = null;
        }
        catch (Exception exc)
        {
            Debug.Log (exc.ToString ());
        }

        mRecvResult = null;
        m_Client = null;
        m_RecvPos = 0;
        m_RecvOverCount = 0;
        m_ConnectOverCount = 0;
        mReceiveStreams.Clear ();
        mReceiveMsgIDs.Clear ();
    }

    //处理Msg
    public void DealWithMsg()
    {
        while (mReceiveMsgIDs.Count > 0 && mReceiveStreams.Count > 0)
        {
            int type = mReceiveMsgIDs [0];
            System.IO.MemoryStream iostream = mReceiveStreams [0];

            //当您调用RemoveAt要删除某个项,在列表中其余项目会重新编号来替换已移除的项.
            mReceiveMsgIDs.RemoveAt (0);
            mReceiveStreams.RemoveAt (0);

            try
            {
                //CGLCtrl_GameLogic.Instance.HandleNetMsg(iostream, type);
                if (mReceiveStreamsPool.Count < 100)
                {
                    mReceiveStreamsPool.Add(iostream);
                }
                else
                {
                    iostream = null;
                }
            }
            catch (Exception exc)
            {
                Debug.LogError("Handle error msgid: " + type);
            }
        }
    }

    public void OnDataReceived(object sender, DataEventArgs e)
    {
        int m_CurPos = 0;

        //因为length和type就占了8字节,所以要大于等于8
        while (m_RecvPos - m_CurPos >= 8)
        {
            //这里和CMemBuffer有点像
            //m_RecvBuffer:第一个四字节:length,length包括了length和type所占用的8个字节
            //m_RecvBuffer:第二个四字节:type
            //m_RecvBuffer:再后面就是data了
            int len = BitConverter.ToInt32 (m_RecvBuffer, m_CurPos);
            int type = BitConverter.ToInt32 (m_RecvBuffer, m_CurPos + 4);

            if (len > m_RecvBuffer.Length)
            {
                Debug.LogError ("cannot pause message" + " type= " + type + " len= " + len);
                break;
            }

            if (len > m_RecvPos - m_CurPos)
            {
                //这时候,data还没接受完
                break;//wait ne recv more buffer to parse.
            }

            //获取stream
            System.IO.MemoryStream tempStream = null;
            if (mReceiveStreamsPool.Count > 0)
            {
                tempStream = mReceiveStreamsPool [0];
                tempStream.SetLength (0);
                tempStream.Position = 0;
                mReceiveStreamsPool.RemoveAt (0);
            }
            else
            {
                tempStream = new System.IO.MemoryStream ();
            }

            //往stream填充网络数据
            tempStream.Write (m_RecvBuffer, m_CurPos + 8, len - 8);
            tempStream.Position = 0;
            m_CurPos += len;

            mReceiveMsgIDs.Add (type);
            mReceiveStreams.Add (tempStream);
        }

        if (m_CurPos > 0)
        {
            //m_RecvPos减去已经读取的字节
            m_RecvPos = m_RecvPos - m_CurPos;

            if (m_RecvPos < 0)
            {
                Debug.LogError ("m_RecvPos < 0");
            }

            if (m_RecvPos > 0)
            {
                Buffer.BlockCopy (m_RecvBuffer, m_CurPos, m_RecvBuffer, 0, m_RecvPos);
            }
        }

    }

}

你可能感兴趣的:(Common(七)—— NetworkManager)