IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> unity网络加载socket -> 正文阅读

[网络协议]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();
??????????????? }
??????????? }
?????????? ?
??????? }
??? }
? ?
}

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-16 12:04:52  更:2021-08-16 12:07:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/17 15:31:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码