一个简易的心跳包 C# Socket (上)
上篇 讲讲 代码 下篇就是讲下示例上面的使用了
先来看看代码吧:
1.KGHeartBeat 单个心跳包的数据类
using System;
namespace KGSocket.Tool
{
public class KGHeartBeat
{
//保存上一次心跳的时间
protected long lastHeartTime;
//超时次数
public int Lostcount;
//心跳包最大超时多少次
public int MaxLostcount;
//超时多久算一次
public double MaxLostTime;
//计算时间差的
public long NowTimeSpan => Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds);
/// <summary>
/// 检查心跳包延时
/// </summary>
public virtual void CheckHeat()
{
if (Math.Abs(lastHeartTime - this.NowTimeSpan) > MaxLostTime)
{
lastHeartTime = this.NowTimeSpan;
Lostcount++;
}
}
/// <summary>
/// 更新心跳包
/// </summary>
public virtual void UpdateHeat()
{
lastHeartTime = this.NowTimeSpan;
Lostcount = 0;
}
public virtual T InitMax<T>(double maxlosttime = 2, int maxlost = 3) where T: KGHeartBeat
{
MaxLostTime = maxlosttime;
MaxLostcount = maxlost;
//第一次赋值肯定要刷新
lastHeartTime = this.NowTimeSpan;
return this as T;
}
public virtual void InitMax(double maxlosttime = 2, int maxlost = 3)
{
MaxLostTime = maxlosttime;
MaxLostcount = maxlost;
//第一次赋值肯定要刷新
lastHeartTime = this.NowTimeSpan;
}
}
}
貌似 都注释上了没啥好说的, NowTimeSpan => Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds); 这个就是一个只读的写法,每次读取都会读现在的时间与默认的时间差距秒,从而去计算心跳包的秒数
InitMax()就是初始化上限数值 超时次数 超时上限
UpdateHeat()就是更新心跳包的 重新赋值当前与默认时间的差距秒数, 如果过段时间不更新不更新当前持有的秒数也不会更新 在CheckHeat()检测超过限定的超时时间MaxLostTime 就是增加一次Lostcount超时次数
2.KGHeartBeatManage<T,R>心跳包的管理类
using System;
using System.Collections.Generic;
namespace KGSocket.Tool
{
public class KGHeartBeatManage<T, R> : IDisposable where R : KGHeartBeat, new()
{
//主定时器
public System.Timers.Timer Checktimer;
public System.Timers.Timer Sendtimer;
private readonly object mlock = new object();
//发送心跳包事件
public event Action<T> SendHearEvent;
//心跳包超时事件
public event Action<T> ConnectLostEvent;
//每个会话对应一个心跳KGHeartBeat
private Dictionary<T, R> connectDic = new Dictionary<T, R>();
public Dictionary<T, R> ConnectDic { get => connectDic; protected set => connectDic = value; }
public virtual KGHeartBeatManage<T, R> InitTimerEvent(Action<T> sendHearEvent, Action<T> connectLostEvent, double Checkinterval = 1000, double Sendinterval = 1000)
{
//这里是赋值每过多少秒执行一次事件
Checktimer = new System.Timers.Timer(Checkinterval);
Sendtimer = new System.Timers.Timer(Sendinterval);
SendHearEvent = sendHearEvent;
ConnectLostEvent = connectLostEvent;
//定时执行事件
Checktimer.Elapsed += (v, f) =>
{
//遍历每个会话回调一次检查心跳包
CheckHeartBeat();
};
//定时执行事件
Sendtimer.Elapsed += (v, f) =>
{
//遍历每个会话回调一次发送心跳包
lock (mlock)
{
SendHeartBeat();
}
};
return this;
}
public virtual KGHeartBeatManage<T, R> StartTimer()
{
Checktimer.Start();
Sendtimer.Start();
return this;
}
public virtual KGHeartBeatManage<T, R> StopTimer()
{
Checktimer.Stop();
Sendtimer.Stop();
return this;
}
/// <summary>
/// 发送心跳包
/// </summary>
public virtual void SendHeartBeat()
{
lock (mlock)
{
if (ConnectDic.Count > 0&& SendHearEvent!=null)
{
List<T> RemoveList = new List<T>();
foreach (KeyValuePair<T, R> item in ConnectDic)
{
SendHearEvent?.Invoke(item.Key);
}
}
}
}
/// <summary>
/// 检查心跳包
/// </summary>
public virtual void CheckHeartBeat()
{
lock (mlock)
{
if (ConnectDic.Count > 0)
{
List<T> RemoveList = new List<T>();
foreach (KeyValuePair<T, R> item in ConnectDic)
{
//检查 心跳包超时 如果超时满次数就移除并回调事件
item.Value.CheckHeat();
if (item.Value.Lostcount >= item.Value.MaxLostcount)
{
RemoveList.Add(item.Key);
}
RemoveList.ForEach(remove =>
{
ConnectLostEvent(remove);
ConnectDic.Remove(remove);
});
}
}
}
}
/// <summary>
/// 添加存储新的心跳包
/// </summary>
/// <param name="obj"></param>
/// <param name="heart"></param>
/// <param name="maxlosttime"></param>
/// <param name="maxlost"></param>
public KGHeartBeatManage<T, R> AddConnectDic(T obj, double maxlosttime = 2, int maxlost = 3)
{
R heartBeat= new R().InitMax<R>(maxlosttime,maxlost);
lock (mlock)
{
ConnectDic.Add(obj, heartBeat);
}
return this;
}
public KGHeartBeatManage<T, R> RemoveConnectDic(T obj)
{
lock (mlock)
{
ConnectDic.Remove(obj);
}
return this;
}
/// <summary>
/// 更新指定会话对应的心跳包
/// </summary>
/// <param name="obj"></param>
public void UpdateOneHeat(T obj)
{
lock (mlock)
{
ConnectDic[obj].UpdateHeat();
}
}
public void Dispose()
{
Checktimer.Dispose();
Sendtimer.Dispose();
}
}
}
KGHeartBeatManage<T,R>:IDisposable where R:KGHeartBeat 这里的T就是你们定义的每个会话管理类,R就是指定要继承KGHeartBeat 的
初始化事件 InitTimerEvent(第一个委托就是发送事件,第二个委托就是 每个心跳包如果超时就会回调回来,每隔多少毫秒触发一次检测,每隔多少毫秒发送心跳包)
然后StartTimer()就可以开始触发了
这边定时器那里加了个每次都会检测ConnectDic字典里面储存的心跳包,如果超过最大上限超时次数就会回调 KGHeartBeatManage里面的第二个委托,告诉他这个连接已经超时,
AddConnectDic(对应的会话管理类,指定超时时间,超时次数)这里会创建出对应的KGHeartBeat数据里存在字典里面,每个会话管理对应一个心跳包数据
RemoveConnectDic(T obj) 这里是移除字典里面 该会话管理对应的心跳包
因为会有多线程触发的问题这里用了lock互斥锁,排队来,
https://github.com/LKaiGuo/KGScriptGenerator 喜欢的给我点个星星啊
u3d萌新QQ群844087555 欢迎进来灌水=。=