Browse Source

【优化】通过配置来开关是否加入心跳检测,参照SessionIdleCheckerComponentSystem

johnclot69 1 year ago
parent
commit
3c14c68607

+ 13 - 5
DotNet/Hotfix/Module/Message/NetServerComponentSystem.cs

@@ -44,12 +44,20 @@ namespace ET.Server
             Session session = self.AddChildWithId<Session, int>(channelId, self.ServiceId);
             session.RemoteAddress = ipEndPoint;
 
-            if (self.DomainScene().SceneType != SceneType.BenchmarkServer)
+            if (self.DomainScene().SceneType == SceneType.BenchmarkServer)
             {
-                // 挂上这个组件,5秒就会删除session,所以客户端验证完成要删除这个组件。该组件的作用就是防止外挂一直连接不发消息也不进行权限验证
-                session.AddComponent<SessionAcceptTimeoutComponent>();
-                // 客户端连接,2秒检查一次recv消息,10秒没有消息则断开
-                session.AddComponent<SessionIdleCheckerComponent>();
+                return;
+            }
+
+            // 挂上这个组件,5秒就会删除session,所以客户端验证完成要删除这个组件。该组件的作用就是防止外挂一直连接不发消息也不进行权限验证
+            session.AddComponent<SessionAcceptTimeoutComponent>();
+            // 客户端连接,2秒检查一次recv消息,10秒没有消息则断开
+            session.AddComponent<SessionIdleCheckerComponent>();
+
+            if (session.DomainScene().SceneType == SceneType.Game && ConstValue.HeartBeatPower == 1)
+            {
+                // 挂上心跳超时检测组件
+                session.AddComponent<HeartBeatTimeoutComponent>();
             }
         }
 

+ 0 - 4
DotNet/Hotfix/Scenes/Game/Handler/C2G_LoginGameHandler.cs

@@ -1,7 +1,4 @@
 using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
 
 namespace ET.Server
 {
@@ -34,7 +31,6 @@ namespace ET.Server
             // 移除session自动超时组件
             session.RemoveComponent<SessionAcceptTimeoutComponent>();
             // 添加session组件,用于绑定角色
-            session.AddComponent<HeartBeatComponent, Session>(session);
             session.AddComponent<SessionPlayerComponent>().RoomId = request.Token.Trim();
             session.AddComponent<MailBoxComponent, MailboxType>(MailboxType.GateSession);
 

+ 3 - 5
DotNet/Hotfix/Scenes/Game/Handler/C2G_PingHandler.cs

@@ -9,11 +9,9 @@ namespace ET.Server
 	public class C2G_PingHandler : AMRpcHandler<C2G_Ping, G2C_Ping>
 	{
 		protected override async ETTask Run(Session session, C2G_Ping request, G2C_Ping response, Action reply)
-		{
-            if (session.GetComponent<HeartBeatComponent>() != null)
-            {
-                session.GetComponent<HeartBeatComponent>().CurrentTime = TimeHelper.ClientNowSeconds();
-            }
+        {
+            session.LastPingTime = TimeHelper.ClientNow();
+
 			response.Time = TimeHelper.ServerNow();
 			reply();
 			await ETTask.CompletedTask;

+ 0 - 43
DotNet/Hotfix/Scenes/Game/Player/HeartBeatComponentSystem.cs

@@ -1,43 +0,0 @@
-namespace ET.Server
-{
-    [FriendOf(typeof (HeartBeatComponent))]
-    public static class HeartBeatComponentSystem
-    {
-        public class HeartBeatComponentAwakeSystem: AwakeSystem<HeartBeatComponent, Session>
-        {
-            protected override void Awake(HeartBeatComponent self, Session session)
-            {
-                // 初始化
-                self.Session = session;
-                self.UpdateInterval = 5;
-                self.OutInterval = 3;
-                self.RecordDeltaTime = 0;
-                self.CurrentTime = 0;
-            }
-        }
-
-        public class HeartBeatComponentUpdateSystem: UpdateSystem<HeartBeatComponent>
-        {
-            protected override void Update(HeartBeatComponent self)
-            {
-                // 如果没有到达发包时间、直接返回
-                if (!((TimeHelper.ClientNowSeconds() - self.RecordDeltaTime) > self.UpdateInterval) || self.CurrentTime == 0)
-                {
-                    return;
-                }
-
-                // 记录当前时间
-                self.RecordDeltaTime = TimeHelper.ClientNowSeconds();
-
-                // 移除Session
-                if (TimeHelper.ClientNowSeconds() - self.CurrentTime <= self.OutInterval)
-                {
-                    return;
-                }
-
-                Log.Debug($"移除Session Parent.Id = {self.Parent.Id}");
-                self.Session.Disconnect().Coroutine();
-            }
-        }
-    }
-}

+ 57 - 0
DotNet/Hotfix/Scenes/Game/Player/HeartBeatTimeoutComponentSystem.cs

@@ -0,0 +1,57 @@
+using System;
+
+namespace ET.Server
+{
+    [Invoke(TimerInvokeType.HeartBeatTimeout)]
+    public class HeartBeatCheck: ATimer<HeartBeatTimeoutComponent>
+    {
+        protected override void Run(HeartBeatTimeoutComponent self)
+        {
+            try
+            {
+                self.Check();
+            }
+            catch (Exception e)
+            {
+                Log.Error($"move timer error: {self.Id}\n{e}");
+            }
+        }
+    }
+
+    [ObjectSystem]
+    public class HeartBeatTimeoutComponentAwakeSystem: AwakeSystem<HeartBeatTimeoutComponent>
+    {
+        protected override void Awake(HeartBeatTimeoutComponent self)
+        {
+            self.Timer = TimerComponent.Instance.NewRepeatedTimer( Math.Max( ConstValue.HeartBeatTimeoutTime, 5 ), TimerInvokeType.HeartBeatTimeout, self);
+        }
+    }
+
+    [ObjectSystem]
+    public class HeartBeatTimeoutComponentDestroySystem: DestroySystem<HeartBeatTimeoutComponent>
+    {
+        protected override void Destroy(HeartBeatTimeoutComponent self)
+        {
+            TimerComponent.Instance?.Remove(ref self.Timer);
+        }
+    }
+
+    public static class HeartBeatTimeoutComponentSystem
+    {
+        public static void Check(this HeartBeatTimeoutComponent self)
+        {
+            Session session = self.GetParent<Session>();
+            long timeNow = TimeHelper.ClientNow();
+
+            if (session.LastPingTime == 0 || timeNow - session.LastPingTime < ConstValue.HeartBeatTimeoutTime)
+            {
+                return;
+            }
+
+            Log.Info($"heartBeat timeout: {session.Id} {timeNow} {session.LastPingTime} {timeNow - session.LastPingTime}");
+            session.Error = ErrorCore.ERR_HeartBeatTimeout;
+
+            session.Dispose();
+        }
+    }
+}

+ 0 - 29
DotNet/Model/Scenes/Game/Player/HeartBeatComponent.cs

@@ -1,29 +0,0 @@
-namespace ET.Server
-{
-    [ComponentOf(typeof (Session))]
-    public class HeartBeatComponent: Entity, IAwake<Session>, IUpdate
-    {
-        public Session Session { get; set; }
-
-        /// <summary>
-        /// 更新间隔
-        /// </summary>
-        public long UpdateInterval { get; set; }
-
-        /// <summary>
-        /// 超出时间
-        /// </summary>
-        /// <remarks>如果跟客户端连接时间间隔大于在服务器上删除该Session</remarks>
-        public long OutInterval { get; set; }
-
-        /// <summary>
-        /// 记录时间
-        ///</summary>
-        public long RecordDeltaTime { get; set; }
-
-        /// <summary>
-        /// 当前Session连接时间
-        /// </summary>
-        public long CurrentTime { get; set; }
-    }
-}

+ 8 - 0
DotNet/Model/Scenes/Game/Player/HeartBeatTimeoutComponent.cs

@@ -0,0 +1,8 @@
+namespace ET.Server
+{
+    [ComponentOf(typeof (Session))]
+    public class HeartBeatTimeoutComponent: Entity, IAwake, IDestroy
+    {
+        public long Timer;
+    }
+}

+ 7 - 1
Unity/Assets/Scripts/Codes/Model/Share/Const/ConstValue.cs

@@ -1,4 +1,6 @@
-namespace ET
+using System;
+
+namespace ET
 {
     /**
      * 静态常量值
@@ -7,6 +9,10 @@
     {
         /** session过期时间 **/
         public const int SessionTimeoutTime = 30 * 1000;
+        /** 心跳开关 **/
+        public static int HeartBeatPower = 1;
+        /** 心跳超时时间 **/
+        public const int HeartBeatTimeoutTime = 3 * 1000;
     }
 
     public enum BattlePushCnst

+ 17 - 11
Unity/Assets/Scripts/Codes/Model/Share/Module/Message/Session.cs

@@ -17,7 +17,7 @@ namespace ET
             this.Tcs = ETTask<IResponse>.Create(true);
         }
     }
-    
+
     [FriendOf(typeof(Session))]
     public static class SessionSystem
     {
@@ -32,29 +32,29 @@ namespace ET
                 self.LastSendTime = timeNow;
 
                 self.requestCallbacks.Clear();
-            
+
                 Log.Info($"session create: zone: {self.DomainZone()} id: {self.Id} {timeNow} ");
             }
         }
-        
+
         [ObjectSystem]
         public class SessionDestroySystem: DestroySystem<Session>
         {
             protected override void Destroy(Session self)
             {
                 NetServices.Instance.RemoveChannel(self.ServiceId, self.Id, self.Error);
-            
+
                 foreach (RpcInfo responseCallback in self.requestCallbacks.Values.ToArray())
                 {
                     responseCallback.Tcs.SetException(new RpcException(self.Error, $"session dispose: {self.Id} {self.RemoteAddress}"));
                 }
 
                 Log.Info($"session dispose: {self.RemoteAddress} id: {self.Id} ErrorCode: {self.Error}, please see ErrorCode.cs! {TimeHelper.ClientNow()}");
-            
+
                 self.requestCallbacks.Clear();
             }
         }
-        
+
         public static void OnResponse(this Session self, IResponse response)
         {
             if (!self.requestCallbacks.TryGetValue(response.RpcId, out var action))
@@ -70,7 +70,7 @@ namespace ET
             }
             action.Tcs.SetResult(response);
         }
-        
+
         public static async ETTask<IResponse> Call(this Session self, IRequest request, ETCancellationToken cancellationToken)
         {
             int rpcId = ++Session.RpcId;
@@ -79,7 +79,7 @@ namespace ET
             request.RpcId = rpcId;
 
             self.Send(request);
-            
+
             void CancelAction()
             {
                 if (!self.requestCallbacks.TryGetValue(rpcId, out RpcInfo action))
@@ -121,7 +121,7 @@ namespace ET
         {
             self.Send(0, message);
         }
-        
+
         public static void Send(this Session self, long actorId, IMessage message)
         {
             self.LastSendTime = TimeHelper.ClientNow();
@@ -134,7 +134,7 @@ namespace ET
     public sealed class Session: Entity, IAwake<int>, IDestroy
     {
         public int ServiceId { get; set; }
-        
+
         public static int RpcId
         {
             get;
@@ -142,7 +142,7 @@ namespace ET
         }
 
         public readonly Dictionary<int, RpcInfo> requestCallbacks = new Dictionary<int, RpcInfo>();
-        
+
         public long LastRecvTime
         {
             get;
@@ -166,5 +166,11 @@ namespace ET
             get;
             set;
         }
+
+        public long LastPingTime
+        {
+            get;
+            set;
+        }
     }
 }

+ 3 - 3
Unity/Assets/Scripts/Codes/Model/Share/TimerInvokeType.cs

@@ -3,16 +3,16 @@
     [UniqueId(100, 10000)]
     public static class TimerInvokeType
     {
-        // 框架层100-200,逻辑层的timer type从200起
+        // 框架层的timer type 100-200
         public const int WaitTimer = 100;
         public const int SessionIdleChecker = 101;
         public const int ActorLocationSenderChecker = 102;
         public const int ActorMessageSenderChecker = 103;
 
-        // 框架层100-200,逻辑层的timer type 200-300
+        // 逻辑层的timer type 200-300
         public const int MoveTimer = 201;
         public const int AITimer = 202;
         public const int SessionAcceptTimeout = 203;
-        public const int LoginTimeout = 204;
+        public const int HeartBeatTimeout = 204;
     }
 }

+ 2 - 0
Unity/Assets/Scripts/Core/Module/Network/ErrorCore.cs

@@ -52,6 +52,8 @@
         public const int ERR_KcpRouterRouterSyncCountTooMuchTimes = 110405;
         public const int ERR_KcpRouterSyncCountTooMuchTimes = 110406;
 
+        public const int ERR_HeartBeatTimeout = 110501;
+
         // 110000 以上,避免跟SocketError冲突