#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(); ??????????????? } ??????????? } ?????????? ? ??????? } ??? } ? ? }
|