ET框架心跳包组件开发
网络游戏经常会发生(玩家断网、电脑死机、等)现象、这些会造成服务器里存在很多Session存在。
为什么Session会一直存在,不会自动销毁吗?因为服务器是不会知道这个Session是不是(玩家断网、电脑死机、等)现象。
断开网络连接需要4次握手才可以完成、但(玩家断网、电脑死机、等)现象是不会有4次握手的。
明白了这个问题,就需要做一个功能那就是每隔一段时间给服务器发送数据,表示我还在跟你连接,如果服务器里发现某个Session长时间没有发包了那就表示这个Session是无效的。
ET很强大,但没有提供这个心跳,需要自己开发一个这样的功能。
设计思路:
- 心跳协议包(进行客户端跟服务端相互通信的数据包)
- 心跳组件(ET是ECS框架也就是组件式、所以要开发出客户端和服务端的组件)
心跳协议包(服务端和客户端都需要):
需要在Opcode.cs里添加两个枚举、分别C2R_HeartBeat、R2C_HeartBeat
public enum Opcode: ushort
{
C2R_HeartBeat = 500,
R2C_HeartBeat = 501
}
需要在OuterMessage.cs文件里的添加两个类、分别C2R_HeartBeat、R2C_HeartBeat
需要在OuterMessage.cs文件里的public partial class ARequest {}上添加
ProtoInclude((int)Opcode.C2R_HeartBeat, typeof(C2R_HeartBeat))]
[BsonKnownTypes(typeof(C2R_HeartBeat))]
需要在OuterMessage.cs文件里的public partial class AResponse {}上添加
[ProtoInclude((int)Opcode.R2C_HeartBeat, typeof(R2C_HeartBeat))]
[BsonKnownTypes(typeof(R2C_HeartBeat))]
服务端心跳组件:
Model项目下Component文件夹下创建HeartBeatComponent.cs文件并使用以下代码
[ObjectSystem]
public class HeartBeatSystem : ObjectSystem<HeartBeatComponent>, IUpdate
{
public void Update()
{
this.Get().Update();
}
}
/// <summary>
/// Session心跳组件(需要挂载到Session上)
/// </summary>
public class HeartBeatComponent : Component
{
/// <summary>
/// 更新间隔
/// </summary>
public long UpdateInterval = 5;
/// <summary>
/// 超出时间
/// </summary>
/// <remarks>如果跟客户端连接时间间隔大于在服务器上删除该Session</remarks>
public long OutInterval = 10;
/// <summary>
/// 记录时间 ///
</summary>
private long _recordDeltaTime = 0;
/// <summary>
/// 当前Session连接时间
/// </summary>
public long CurrentTime = 0; public void Update()
{
// 如果没有到达发包时间、直接返回
if (!((TimeHelper.ClientNowSeconds() – this._recordDeltaTime) > this.UpdateInterval) || CurrentTime == 0) return;
// 记录当前时间
this._recordDeltaTime = TimeHelper.ClientNowSeconds();
if ((TimeHelper.ClientNowSeconds() – CurrentTime) > OutInterval)
{
// 移除Session
Game.Scene.GetComponent<NetOuterComponent>().Remove(this.Parent.Id);
Game.Scene.GetComponent<NetInnerComponent>().Remove(this.Parent.Id);
Game.Scene.GetComponent<GateSessionKeyComponent>().Remove(this.Parent.Id);
}
}
}
这段代码实现的功能是每隔一段时间检查当前Session连接时间是否超过OutInterval设定的时间,如果超过那就表示客户端可能是断线了。
那就需要把这个Session给销毁掉。
服务端挂载心跳组件:
需要挂载到网关服务器上。
添加心跳组件:session.AddComponent<HeartBeatComponent>().CurrentTime = TimeHelper.ClientNowSeconds();
在R2G_GetLoginKeyHandler.cs文件里挂载上心跳组件
CurrentTime是当前连接时间,服务端每次接收到客户端的心跳包都会把服务器时间更新到CurrentTime里。
有了CurrentTime的时间就可以判断客户端是否掉线。
Session是每个客户端的连接、我需要把心跳组件挂载到Session上,这样就能实时监测每个Session的状态,如果是断开的就把自己销毁掉。
服务端收发心跳包:
在Hotfix项目Handler文件夹下创建C2R_HeartBeatHandler.cs并使用以下代码
[MessageHandler(AppType.Gate)]
public class C2R_HeartBeatHandler : AMRpcHandler<C2R_HeartBeat, R2C_HeartBeat>
{
protected override void Run(Session session, C2R_HeartBeat message, Action<R2C_HeartBeat> reply)
{
if (session.GetComponent<HeartBeatComponent>() != null)
{
session.GetComponent<HeartBeatComponent>().CurrentTime = TimeHelper.ClientNowSeconds();
}
reply(new R2C_HeartBeat());
}
}
找到Session并更新下HeartBeatComponent的连接时间
客户端心跳组件:
的Component文件夹下创建HeartBeatComponent.cs文件,并使用以下代码
[ObjectSystem]
public class HeartBeatSystem : ObjectSystem<HeartBeatComponent>,IUpdate
{
public void Update()
{
this.Get().Update();
}
}
/// <summary>
/// Session心跳组件(需要挂载到Session上)
/// </summary>
public class HeartBeatComponent: Component
{
/// <summary>
/// 心跳包间隔
/// </summary>
public float SendInterval = 2f;
/// <summary>
/// 记录时间
/// </summary>
private float RecordDeltaTime = 0f;
public async void Update()
{
// 如果还没有建立Session直接返回、或者没有到达发包时间
if (!((Time.time – this.RecordDeltaTime) > this.SendInterval)) return;
// 记录当前时间
this.RecordDeltaTime = Time.time;
// 开始发包
try
{
R2C_HeartBeat result = (R2C_HeartBeat) await this.GetParent<Session>().Call(new C2R_HeartBeat());
}
catch
{
// 执行断线后的操作 Debug.Log(“断线了”);
}
}
}
客户端挂载心跳组件:
Game.Scene.GetComponent<SessionComponent>().Session.AddComponent<HeartBeatComponent>();
这个组件挂载什么位置看个人而定,我是挂载到第一次跟服务器通讯的地方了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)