ET5.0-添加心跳功能
ET5.0 demo中添加心跳功能
一、服务端
1:添加文件夹,在Model/Module文件夹下新建文件夹 Hearbeat

2:添加心跳配置文件 SessionHeartbeatComponentAwakeSystem
namespace ETModel
{
[ObjectSystem]
public class SessionHeartbeatComponentAwakeSystem : AwakeSystem<SessionHeartbeatComponent>
{
public override void Awake(SessionHeartbeatComponent self)
{
HeartbeatMgrComponent.Ins.AddSessionHeartbeat(self);
}
} public class SessionHeartbeatComponent: Component
{
public const int DestroySeesiontTime = 40;//多长 时间 没收到客户端消息 就直接销毁
public const int DestroySeesiontSecondTotalNum = 10;//一秒内收到多少条消息 就直接销毁 public int SecondTotalMessageNum = 0;//一秒内 累计收到的消息条数
public int UpReceiveMessageDistance = 0;//距离上次收到消息 有多长时间 //销毁Session
public void DisposeSession()
{
Entity.Dispose();
}
public override void Dispose()
{
HeartbeatMgrComponent.Ins.RemoveSessionHeartbeat(InstanceId);//必须在 base.Dispose(); 前面调 因为 Dispose会吧id置为0
base.Dispose();
SecondTotalMessageNum = 0;//一秒内 累计收到的消息条数
UpReceiveMessageDistance = 0;//距离上次收到消息 有多长时间
}
}
}
3、添加心跳检测组件 HeartbeatMgrComponentAwakeSystem
using System.Collections.Generic; namespace ETModel
{
[ObjectSystem]
public class HeartbeatMgrComponentAwakeSystem: AwakeSystem<HeartbeatMgrComponent>
{
// public static List<SessionHeartbeatComponent> _DestroyHeartbeatComponents = new List<SessionHeartbeatComponent>();
public override void Awake(HeartbeatMgrComponent self)
{
HeartbeatMgrComponent.Ins = self;
self.Awake();
}
} public class HeartbeatMgrComponent: Component
{
public List<long> SessionHeartbeatIds = new List<long>();
public Dictionary<long, SessionHeartbeatComponent> SessionHeartbeatDic = new Dictionary<long, SessionHeartbeatComponent>();
public static HeartbeatMgrComponent Ins { get; set; } public async void Awake()
{
while (true)
{
await Game.Scene.GetComponent<TimerComponent>().WaitAsync(1000);
for (int i = 0; i < SessionHeartbeatIds.Count; i++)
{
//一秒内收到消息的数量
SessionHeartbeatDic[SessionHeartbeatIds[i]].SecondTotalMessageNum = 0;
SessionHeartbeatDic[SessionHeartbeatIds[i]].UpReceiveMessageDistance++; if (SessionHeartbeatDic[SessionHeartbeatIds[i]].UpReceiveMessageDistance>=
SessionHeartbeatComponent.DestroySeesiontTime)
{
SessionHeartbeatDic[SessionHeartbeatIds[i]].DisposeSession();//如果上次收到时间 过长 就直接销毁DisposeSession
}
}
}
} /// <summary>
/// 添加SessionHeartbeat 组件
/// </summary>
/// <param name="sessionHeartbeat"></param>
public void AddSessionHeartbeat(SessionHeartbeatComponent sessionHeartbeat)
{
SessionHeartbeatDic[sessionHeartbeat.InstanceId] = sessionHeartbeat;
SessionHeartbeatIds.Add(sessionHeartbeat.InstanceId);
} /// <summary>
/// 移除组件
/// </summary>
/// <param name="id"></param>
public void RemoveSessionHeartbeat(long id)
{
if (SessionHeartbeatDic.ContainsKey(id))
{
SessionHeartbeatDic.Remove(id);
SessionHeartbeatIds.Remove(id);
}
} } }
4、添加Session挂载心跳组件 SessionHeartbeatAwakeSystem
namespace ETModel
{
[ObjectSystem]
public class SessionHeartbeatAwakeSystem:AwakeSystem<Session, AChannel>
{
public override void Awake(Session self, AChannel a)
{
if (self.Network.AppType==AppType.None)//不是任何APPType 就是客户端
{
self.AddComponent<SessionHeartbeatComponent>();
}
}
}
}
5、Program.cs 文件在 AppType.AllServer中挂载心跳组件
//与客户端有连接都要加
Game.Scene.AddComponent<HeartbeatMgrComponent>();//心跳管理组件 验证服 也是要加的
6、处理心跳消息,在OuterMessage.proto 添加
//心跳消息
message C2G_Heartbeat // IMessage
{
int32 RpcId = 90;
}
在 OuterMessageDispatcher 文件中添加心跳逻辑处理
using ETModel; namespace ETHotfix
{
public class OuterMessageDispatcher: IMessageDispatcher
{
public void Dispatch(Session session, ushort opcode, object message)
{
DispatchAsync(session, opcode, message).Coroutine();
} public async ETVoid DispatchAsync(Session session, ushort opcode, object message)
{
/********* 添加心跳修改 **************/
SessionHeartbeatComponent sessionHeartbeatComponent = session.GetComponent<SessionHeartbeatComponent>();
if (sessionHeartbeatComponent == null)
{
Log.Info("---not heartbeat compinent---");
session.Dispose();//心跳组件 没有 直接销毁
return;
}
sessionHeartbeatComponent.UpReceiveMessageDistance = 0;//重置上次收到消息的时间
//如果收到 一秒收到的消息 大于规定的消息 就认定是DOSS攻击 直接销毁
if (++sessionHeartbeatComponent.SecondTotalMessageNum >=
SessionHeartbeatComponent.DestroySeesiontSecondTotalNum)
{
//断开连接
sessionHeartbeatComponent.DisposeSession();
//直接封号
// UserHelp.StopSealOrRelieve(sessionUserComponent.UserId,true,"DOSS攻击封号"); //不要封号容易误封
return;
}
/********* 添加心跳修改 **************/ // 根据消息接口判断是不是Actor消息,不同的接口做不同的处理
switch (message)
{
case IActorLocationRequest actorLocationRequest: // gate session收到actor rpc消息,先向actor 发送rpc请求,再将请求结果返回客户端
{
long unitId = session.GetComponent<SessionPlayerComponent>().Player.UnitId;
ActorLocationSender actorLocationSender = await Game.Scene.GetComponent<ActorLocationSenderComponent>().Get(unitId); int rpcId = actorLocationRequest.RpcId; // 这里要保存客户端的rpcId
long instanceId = session.InstanceId;
IResponse response = await actorLocationSender.Call(actorLocationRequest);
response.RpcId = rpcId; // session可能已经断开了,所以这里需要判断
if (session.InstanceId == instanceId)
{
session.Reply(response);
} break;
}
case IActorLocationMessage actorLocationMessage:
{
long unitId = session.GetComponent<SessionPlayerComponent>().Player.UnitId;
ActorLocationSender actorLocationSender = await Game.Scene.GetComponent<ActorLocationSenderComponent>().Get(unitId);
actorLocationSender.Send(actorLocationMessage).Coroutine();
break;
}
case IActorRequest actorRequest: // 分发IActorRequest消息,目前没有用到,需要的自己添加
{
break;
}
case IActorMessage actorMessage: // 分发IActorMessage消息,目前没有用到,需要的自己添加
{
break;
}
case C2G_Heartbeat c2GHeartbeat: //单独处理心跳
{
//心跳不做处理
Log.Info("--收到心跳--");
break;
}
default:
{
// 非Actor消息
Game.Scene.GetComponent<MessageDispatcherComponent>().Handle(session, new MessageInfo(opcode, message));
break;
}
}
}
}
}
7、重新编译
二、客户端
1、在客户端 Assets/Hotfix/Module/Demo新建文件 HeartbeatComponent
using ETModel; namespace ETHotfix
{
[ObjectSystem]
public class HeartbeatComponentAwakeSystem: AwakeSystem<HeartbeatComponent>
{
public override void Awake(HeartbeatComponent self)
{
self.Awake();
} public async void DetectionNetworkType(Session session)
{
// while (!session.IsDisposed)
// {
// await ETModel.Game.Scene.GetComponent<TimerComponent>().WaitAsync(1000);
// //如果当前是无网络状态 发送连接失败的消息
// if (NetworkType.None == SdkMgr.Ins.GetNetworkInfo())
// {
// session.session.Error = (int) SocketError.NetworkDown;
// session.Dispose();
// }
// }
}
} /// <summary>
/// 心跳组件
/// </summary>
public class HeartbeatComponent: Component
{
public static C2G_Heartbeat heartBeat = new C2G_Heartbeat(); public async void Awake()
{
//每间隔10秒发一条 心跳消息
// DetectionNetworkType(session);//检测网络连接状态
Log.Debug("--status:" + !IsDisposed);
while (!IsDisposed)
{
await ETModel.Game.Scene.GetComponent<TimerComponent>().WaitAsync(10000); Log.Debug("--ping---" + ETModel.SessionComponent.Instance.Session.IsDisposed); if (ETModel.SessionComponent.Instance.Session.IsDisposed)
{
Log.Error("--服务器连接断开-");
} ETModel.SessionComponent.Instance.Session.Send(heartBeat);
}
}
}
}
运行:
1、重新编译服务器,并运行。不要移动小人,停止40秒(服务端配置的是40秒)左右,服务器会断开客户端。

2、修改客户端,挂载心跳组件发送心跳
我是在登录gate服务器成功时添加的组件,文件LoginHelper.cs中添加组件
//挂载心跳组建
Game.Scene.GetComponent<SessionComponent>().Session.AddComponent<HeartbeatComponent>();

3、再次运行,不会断开客户端。服务器每隔10秒收到心跳消息。

注意:这里只处理了服务端检测心跳,去掉无心跳的链接。没有处理客户端的连接状态。可以将心跳消息修改为 IRequest,通过Call方式发生心跳。

心跳组件参考: 五星麻将的心跳组件。
ET5.0-添加心跳功能的更多相关文章
- layui-treeTable v2.0添加搜索功能
layui-treeTable 添加搜索功能 在树形表格头部加一个input框: <div class="layui-inline"> <input class= ...
- 创建ASP.NET Core MVC应用程序(5)-添加查询功能 & 新字段
创建ASP.NET Core MVC应用程序(5)-添加查询功能 & 新字段 添加查询功能 本文将实现通过Name查询用户信息. 首先更新GetAll方法以启用查询: public async ...
- 033医疗项目-模块三:药品供应商目录模块——供货商药品目录t添加查询功能----------Dao层和Service层和Action层和调试
什么叫做供货商药品目录t添加查询功能?就是说我们前面的博客里面不是说供货商登录后看到了自己供应的药品了么如下: 现在供货商想要往里面添加别的药品,那么这个药品的来源就是卫生局提供的那个Ypxx表(药品 ...
- (三)开始在OJ上添加签到功能
在了解完OJ文件下的各个文件夹的主要作用后,我们开始往里面添加东西(其实只要知道各文件夹是干什么的后,添加东西也变得非常简单了) 一 在数据库中添加对应功能的字段. 我们这个学期才刚开数据库这门课,所 ...
- 给destoon商城的列表中和首页添加购物车功能
如何给destoon商城的列表中和首页添加购物车功能? 目前加入购物车的功能只存在商城的详细页面里,有时候我们需要批量购买的时候,希望在列表页就能够使用这个加入购物车的功能. 修改步骤见下: 例如在商 ...
- lucene3.6笔记添加搜索功能
lucene为程序添加搜索功能,此功能基于已创建好的文档的索引之上.这里我已经为一些文档建立了索引,并保存到硬盘上.下面开始针对这些索引,添加搜索功能. 1.简单的TermQuery搜索 Java代码 ...
- 在VC中,为图片按钮添加一些功能提示(转)
在VC中,也常常为一些图片按钮添加一些功能提示.下面讲解实现过程:该功能的实现主要是用CToolTipCtrl类.该类在VC msdn中有详细说明.首先在对话框的头文件中加入初始化语句:public ...
- Swift - 给表格添加编辑功能(删除,插入)
1,下面的样例是给表格UITableView添加编辑功能: (1)给表格添加长按功能,长按后表格进入编辑状态 (2)在编辑状态下,第一个分组处于删除状态,第二个分组处于插入状态 (3)点击删除图标,删 ...
- 【百度地图API】情人节求爱大作战——添加标注功能
原文:[百度地图API]情人节求爱大作战--添加标注功能 任务描述: 2月2日是除夕,2月14立马来!即将到来的情人节,你想送TA一份什么礼物呢? 不如,在你们居住的地方,画个大大的桃心,表达你对TA ...
- JS实现为控件添加倒计时功能
一.概述 在有些报表需求中,需要为控件添加倒计时功能,限制到某一个时间点后能进行一项操作或不能进行某项操作,比如查询,导出功能等等,又需要人性化地显示还有多少时间,即倒计时功能,比如下图中我们限制这个 ...
随机推荐
- Git提交历史优化指南:两步合并本地Commit,代码审查更高效!
在开发过程中,频繁的本地Commit可能导致提交历史冗杂,增加代码审查和维护的复杂度.通过合并连续的Commit,不仅能简化历史记录,还能提升代码可读性和团队协作效率,以下是合并两次本地Commit的 ...
- APEX实战第3篇:如何完善项目基础功能
上一篇<APEX实战第2篇:构建自己第一个APEX程序>虽然有了程序,但实在是太单薄! 本篇将会介绍一些数据库的基础知识,演示如何通过函数.触发器.存储过程.视图等来完善项目的一些基础功能 ...
- Browser-use:基于 Python 的智能浏览器自动化 AI 工具调研与实战
Browser-use:基于 Python 的智能浏览器自动化 AI 工具调研与实战 一.概述 Browser-use 是一个旨在将 AI "智能体"(Agents)与真实浏览器进 ...
- javaWeb之路径
一. 路径写法: 1. 路径分类 a. 相对路径:通过相对路径不可以确定唯一资源 * 如:./index.html * 不以/开头,以.开头路径 * 规则:找到当前资源和目标资源之间的相对位置关系 * ...
- 用ResourceHacker修改EXE图标
1.打开ResourceHacker.exe 2.点击文件-打开-选择你需要修改的exe文件 3.点击操作-添加图像或二进制文件 4.点击选择文件-选择ico图标-添加资源 5.点击绿色保存图标 6. ...
- Asp.net mvc基础(三)View的查找
1.指定转到的视图 View("指定的视图名称"); 优先于寻找Action方法名称可以创建的视图的文件夹,如果没有,就去View文件夹下的Shared文件夹寻找指定的视图名称. ...
- krpano.js导出为模块方便vue等框架使用的问题
作为一个全栈(干),前端commonjs amd 那些东西没有研究过,一直用es6内置的export和import(不香吗?).最近写一个全景项目,有一个krpano.js文件官网案例是标签引入,可我 ...
- Java AI(智能体)编排开发就用 Solon Flow
本例参考 dify 的 chatFlow 的效果,模拟实现视频内容: https://www.toutiao.com/video/7455114080131482152/ Solon Flow 是一个 ...
- python基础必练题!!
水仙花数 水仙花数 info = 3 while info: # 用户输入数字 try: print(f"请输入数字,您有{info}次机会!!") num = int(input ...
- spring boot迁移计划 第Ⅰ章 --chapter 1. rust hyper 结合rust nacos-client开发nacos网关 part ② hyper网关
1. toml依赖 hyper = { version = "1", features = ["full"] } tokio = { version = &qu ...