unity网络加载socket

#define Test

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
using System.Linq;
using Newtonsoft.Json;
using System.IO;
using System.Reflection;

namespace NCFramework
{
    public class NetService : SingleTon<NetService>, IService,IDisposable
    {
       
        /*
            随笔
            客户端的数据与服务端的数据相差3帧左右,对于客户端来说,所有的数据全部放在队列里面,在处理网络抖动的时候,驱动队列里面的数据来平滑相关的操作,
            数据链的格式以链表的形式存在,因为UDP是不可靠的,数据的到来不一定按照顺序的,所以会进行部分的增删插入的操作
             
            

       */

        #region Init
        private NetService() { }

        public string Name => ServiceInfoCfg.NetName;

        public byte ID => ServiceInfoCfg.NetID;

        public void Init()
        {
            Debug.Log("当前服务ID:" + ID + "====" + "当前服务Name:" + Name);
            ProtoInit();
            UDP();
            LogicInit();

        }
        #endregion
        

        private UInt32 frameCount = 0;
        private AddressFamily IPProtocol = AddressFamily.InterNetwork;//目前暂定为IPV4
        private Socket tcpClient;
        private Socket udpClient;

        private long realtimeSinceStartup = DateTimeUtil.DateTimeToLongTimeStamp(DateTime.Now);

        private long m_LastUpdateShowTime = 0;    //上一次更新帧率的时间;
        private Socket server;
        private EndPoint ClientPoint;

        private Queue<IMessage> receiveQueue = new Queue<IMessage>();

        private Queue<IMessage> sendQueue = new Queue<IMessage>();
        private byte[] data = new byte[ConfigInfo.BufferSize];


        //业务逻辑库
        private Dictionary<int, Func<byte[], int>> allMethodsDic = new Dictionary<int, Func<byte[], int>>();

        #region TCP
        public void TcpInit()
        {
            tcpClient = new Socket(IPProtocol, SocketType.Stream, ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse(ConfigInfo.ServerIP);
            IPEndPoint point = new IPEndPoint(ip, ConfigInfo.ServerPort);
            try
            {
                tcpClient.Connect(point);
                Thread th = new Thread(TcpReceiveMsg);
                th.IsBackground = true;
                th.Start();

            }
            catch (Exception ex)
            {
                //打印异常信息,后续添加到日志中
            }
            finally
            {
                //可能会有超时重连
            }
        }

        void TcpReceiveMsg()
        {
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[ConfigInfo.BufferSize];
                    int n = tcpClient.Receive(buffer);
                    string s = Encoding.UTF8.GetString(buffer, 0, n);
                }
                catch (Exception ex)
                {
                    //添加异常信息
                }
                
            }
        }


        #endregion

        #region UDP
        Thread Udpthread;
        private void UDP()
        {
            //构建UCP 服务器

            Debug.Log("This is a Client, host name is "+ Dns.GetHostName());

            //设置服务IP,设置UDP端口号
            IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ConfigInfo.ServerIP), ConfigInfo.ServerPort);

            //定义网络类型,数据连接类型和网络协议UDP
            server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            server.Bind(new IPEndPoint(IPAddress.Parse(ConfigInfo.LocalIP), ConfigInfo.LocalPort));
            string welcome = "Hello! ";
            data = Encoding.ASCII.GetBytes(welcome);
            server.SendTo(data, data.Length, SocketFlags.None, ipep);
            //这个只是作为临时的发送对象,真正的主角是socket绑定的
            IPEndPoint sender = new IPEndPoint(IPAddress.Any,0);
            ClientPoint = (EndPoint)sender;
           
            //server.Bind(ClientPoint);
            data = new byte[1024];
            //对于不存在的IP地址,加入此行代码后,可以在指定时间内解除阻塞模式限制
            //server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 100);
            int recv = server.ReceiveFrom(data, ref ClientPoint);
            //使用Net自身还是Unity,根据后期测试情况来确定
#warning   目前不确定是依靠Unity驱动还是线程驱动
            Udpthread = new Thread(()=>{
                 while (true)
                 {
                    ReceiveData();
                 }
             });

            Udpthread.IsBackground = true;
            Udpthread.Start();
        }


        #endregion

        public void SendToQueue(byte[] buffer)
        {
            try
            {
                server.SendTo(buffer, ClientPoint);
            }
            catch
            {
                Debug.LogError(DateTime.Now.ToString()+"     发送队列失败");
                //添加相关的IMessage
            }
        }
     
        /// <summary>
        /// 数据接收以及处理流程
        /// </summary>
        /// <param name="buffer"></param>
        private void ReceiveData()
        {
           // try
            {
                int recv = server.ReceiveFrom(data, ref ClientPoint);
                byte[] buffer = new byte[recv];
                Array.Copy(data, buffer, recv);
                ReceiveData(buffer);
            }
            //catch (Exception ex)
            {
               // Debug.LogError("远程主机连接失败,开启重连机制"+ex.ToString());
            }
        }

        /// <summary>
        /// 后期将拆分所有的子功能
        /// </summary>
        /// <param name="data"></param>
        public void ReceiveData(byte[] data)
        {
            //记录其Socket,记录所有的客户端

            // Head + 地址码 + 功能码 + 数据 + 校验码 + tail
            // 数据   {remote信息}
            byte addressCode = data[1];
            byte funCode = data[2];
            byte[] buffer = new byte[data.Length - 6];
            Array.Copy(data, 3, buffer, 0, buffer.Length);
            int key = (addressCode << 8) + funCode;
            allMethodsDic[key].Invoke(buffer);

        }

        /// <summary>
        /// 需要主意的是缓冲的大小必须大于创建的长度
        /// </summary>
        /// <returns></returns>
        public byte[] CreateBuffers(byte addressCode,byte funCode,byte[] data)
        {
            List<byte> buffer = new List<byte>();

            buffer.Add(ProtocalDataConfig.Head);
            buffer.Add(addressCode);
            buffer.Add(funCode);
            buffer.AddRange(data);
            byte[] crc = ByteConvertHelper.CRC16(buffer);
            buffer.AddRange(crc);
            buffer.Add(ProtocalDataConfig.Tail);
            return buffer.ToArray();
        }

        public byte[] CreateBattleBuffers(byte addressCode, byte funCode,Player player,List<IProtoBufBaseData> protoBufBaseDatas)
        {

            List<byte> data = new List<byte>();
            data.Add(player.RoomID);
            data.AddRange(ByteConvertHelper.UInt32ToByteArray(frameCount));
            data.Add(player.PlayerID);

            data.Add(Convert.ToByte(protoBufBaseDatas.Count));

            // Head + 地址码  +  功能码 +{    roomid  +    id  +    帧号    +  子协议数量    +       子协议名称集     +         各个子协议的长度        +    子协议数据集  +   校验码 }  + tail

            List<DataItem> list = new List<DataItem>();
            for (int i = 0; i < protoBufBaseDatas.Count; i++)
            {
                byte[] buffer = ProrocolTool.Serialize(protoBufBaseDatas[i]);
                string name = protoBufBaseDatas[i].GetType().Name;
                list.Add(new DataItem() { Name = ModelDataConfig.ModelDataDic[name], Data = buffer });
            }

            //数据ID
            for (int i = 0; i < list.Count; i++)
            {
                data.Add(list[i].Name);
            }

            //该数据长度
            for (int i = 0; i < list.Count; i++)
            {
                data.Add(Convert.ToByte(list[i].Data.Length));
            }

            //数据
            for (int i = 0; i < list.Count; i++)
            {
                data.AddRange(list[i].Data);
            }

            return CreateBuffers(addressCode,funCode, data.ToArray());
        }


        

        public Dictionary<byte, IProtoBufBaseData> ProtosDic = new Dictionary<byte, IProtoBufBaseData>();
        public void ProtoInit()
        {
            ProtosDic.Add(ProtocalDataConfig.MoveID,new MoveData());
            ProtosDic.Add(ProtocalDataConfig.SkillID, new SkillData());
            ProtosDic.Add(ProtocalDataConfig.ChatID, new ChatData());
        }
        Thread battleTh;
        long currentTime;


        public void CacheData()
        {

            byte[] battleData = NetService.Instance.CreateBattleBuffers
            (
                ProtocalDataConfig.Battle_ID,
                ProtocalDataConfig.Battling_ID,
                GlobalStaticData.Player,
                SenceMiddleWareData.BattleDataList.Values.ToList()
             );
            Debug.Log("发送数据");
            SendToQueue(battleData);

        }


        //定时发送数据
        public void StartBattle()
        {
            battleTh = new Thread(()=> {
                while (true)
                {
                    currentTime = DateTimeUtil.DateTimeToLongTimeStamp(DateTime.Now);
                    if (currentTime- m_LastUpdateShowTime>ConfigInfo.Interval)
                    {
                        CacheData();
                        m_LastUpdateShowTime = DateTimeUtil.DateTimeToLongTimeStamp(DateTime.Now);
                    }
                }
            });

            battleTh.Start();

        }

        /// <summary>
        /// 接收到的完整的数据
        /// </summary>
        /// <param name="data"></param>
        public void DeSerlizeBattleData(byte[] data)
        {
            /*
             *Head      +     地址码     +      功能码        +      
             roomid     +     帧号
             data[0]         data[1]           data[2]              data[3]     data[4]
              [
                    {   该数据的长度   +   id    +   子协议数量    +  子协议名称集     +    各个子协议的长度    +   子协议数据集}  +

                    {   该数据的长度   +   id    +   子协议数量    +  子协议名称集     +    各个子协议的长度    +   子协议数据集}  +

                    {   该数据的长度   +   id    +   子协议数量    +  子协议名称集     +    各个子协议的长度    +   子协议数据集}  +

                    校验码
               ]
               + tail
            */

#if Test && false
            return;

#else
            // byte head = data[0];//head
            //byte addressCode = data[1];//地址码
            //byte funCode = data[2];//功能码


            byte roomID = data[0]; //房间ID

            byte[] frameBuffer = new byte[4];
            UInt32 tempframeCount = 0;//发送的帧索引
            Array.Copy(data, 1, frameBuffer, 0, 4);
            tempframeCount = ByteConvertHelper.BytesToUInt32(frameBuffer);

            //对该房间的所有的人数进行数据划分
            int offset = 0;
            for (int i = 0; i < ConfigInfo.MaxPlayers; i++)
            {
                byte[] subData = new byte[data[5 + offset]];
                Array.Copy(data, 5 + offset, subData, 0, data[5 + offset]);
                offset += data[8 + offset];
                //获取到各个的同步数据

                //{ 该数据的长度 + id + 子协议数量 + 子协议名称集 + 各个子协议的长度 + 子协议数据集}
                byte length = subData[0];
                byte playerId = subData[1];
                byte subCount = subData[2];
                byte[] subNames = new byte[subCount];
                Array.Copy(subData, 3, subNames, 0, subCount);

                byte[] subLengths = new byte[subCount];
                Array.Copy(subData, 3 + subCount, subLengths, 0, subCount);

                int subOffset = 1 + subCount * 2;
                for (int j = 0; j < subCount; j++)
                {
                    byte[] subProData = new byte[subLengths[j]];
                    Array.Copy(subData, subOffset, subProData, 0, subLengths[j]);

                    switch (subNames[j])
                    {
                        case ProtocalDataConfig.MoveID:
                            Debug.Log(subData[1] + ":" + ProtocalDataConfig.MoveID);
                            break;


                        case ProtocalDataConfig.SkillID:
                            Debug.Log(subData[1] + ":" + ProtocalDataConfig.SkillID);
                            break;
                    }
                    subOffset += subLengths[j];

                }
            }
            frameCount++;
            Debug.Log($"当前是第{frameCount}帧");
#endif

        }


        /// <summary>
        /// 业务逻辑注册
        /// </summary>
        private void LogicInit()
        {
            BaseNetLogic netLogic = new BaseNetLogic();
            BindingFlags flag = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
            var infos = netLogic.GetType().GetMethods(flag);
            foreach (var item in infos)
            {
                object[] parameters = new object[] { new byte[] { 0x00, 0x11 } };
                object target = netLogic;
                Func<byte[], int> del = Delegate.CreateDelegate(typeof(Func<byte[], int>), target, item) as Func<byte[], int>; // 创建一个EventHandler类型的委托
                var obj = item.Invoke(netLogic, parameters);
                allMethodsDic.Add(int.Parse(obj.ToString()), del);
            }

            GlobalStaticData.NetLogicFlag = true;
        }


        
        public void Dispose()
        {
            Debug.Log("程序线程退出");
            if (Udpthread!=null)
            {
                if (Udpthread.IsAlive)
                {
                    Udpthread.Abort();
                }
            }

            if (battleTh != null)
            {
                if (battleTh.IsAlive)
                {

                    battleTh.Abort();
                }
            }
            
        }
    }
   
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值