文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

怎么在c#中利用socket实现一个心跳超时检测的功能

2023-06-07 23:18

关注

怎么在c#中利用socket实现一个心跳超时检测的功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

1 内存布局图

怎么在c#中利用socket实现一个心跳超时检测的功能

假设socket3有新的数据到达,需要更新socket3所在的时间轴,处理逻辑如下:

怎么在c#中利用socket实现一个心跳超时检测的功能

2 处理过程分析:

基本的处理思路就是增加时间轴概念。将socket按最后更新时间排序。因为时间是连续的,不可能将时间分割太细。首先将时间离散,比如属于同一秒内的更新,被认为是属于同一个时间点。离散的时间间隔称为时间刻度,该刻度值可以根据具体情况调整。刻度值越小,超时计算越精确;但是计算量增大。如果时间刻度为10毫秒,则一秒的时间长度被划分为100份。所以需要对更新时间做规整,代码如下:

DateTime CreateNow() {  DateTime now = DateTime.Now;  int m = 0;   if(now.Millisecond != 0)  {  if(_minimumScaleOfMillisecond == 1000)  {   now = now.AddSeconds(1); //尾数加1,确保超时值大于 给定的值  }  else  {   //如果now.Millisecond为16毫秒,精确度为10毫秒。则转换后为20毫秒   m = now.Millisecond - now.Millisecond % _minimumScaleOfMillisecond + _minimumScaleOfMillisecond;   if(m>=1000)   {   m -= 1000;   now = now.AddSeconds(1);   }  }  }  return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second,m); }

属于同一个时间刻度的socket,被放入在一个哈希表中(见图中Group)。存放socket的类如下:

class SameTimeKeyGroup<T> { DateTime _timeStamp; public DateTime TimeStamp => _timeStamp; public SameTimeKeyGroup(DateTime time) {  _timeStamp = time; } public HashSet<T> KeyGroup { get; set; } = new HashSet<T>(); public bool ContainKey(T key) {  return KeyGroup.Contains(key); } internal void AddKey(T key) {  KeyGroup.Add(key); } internal bool RemoveKey(T key) {  return KeyGroup.Remove(key); } }

 定义一个List表示时间轴:

List<SameTimeKeyGroup<T>> _listTimeScale = new List<SameTimeKeyGroup<T>>();

 在_listTimeScale 前端的时间较旧,所以链表前端就是有可能超时的socket。

当有socket需要更新时,需要快速知道socket所在的group。这样才能将socket从旧的group移走,再添加到新的group中。需要新增一个链表:

 Dictionary<T, SameTimeKeyGroup<T>> _socketToSameTimeKeyGroup = new Dictionary<T, SameTimeKeyGroup<T>>();

2.1 当socket有新的数据到达时,处理步骤:

public void UpdateTime(T key) {  DateTime now = CreateNow();  //是否已存在,从上一个时间群组删除  if (_socketToSameTimeKeyGroup.ContainsKey(key))  {  SameTimeKeyGroup<T> group = _socketToSameTimeKeyGroup[key];  if (group.ContainKey(key))  {   if (group.TimeStamp == now) //同一时间更新,无需移动   {   return;   }   else   {   group.RemoveKey(key);   _socketToSameTimeKeyGroup.Remove(key);   }  }  }  //从超时组 删除  _timeoutSocketGroup.Remove(key);  //加入到新组  SameTimeKeyGroup<T> groupFromScaleList = GetOrCreateSocketGroup(now, out bool newCreate);  groupFromScaleList.AddKey(key);  _socketToSameTimeKeyGroup.Add(key, groupFromScaleList);  if (newCreate)  {  AdjustTimeout();  } }

2.2 获取超时的socket

 时间轴从旧到新,对比群组的时间与超时时刻。就是链表_listTimeScale,从0开始查找。

/// <summary> ///timeLimit 值为超时时刻限制  ///比如DateTime.Now.AddMilliseconds(-1000);表示 返回一秒钟以前的数据 /// </summary> /// <param name="timeLimit">该时间以前的socket会被返回</param> /// <returns></returns> public List<T> GetTimeoutValue(DateTime timeLimit, bool remove = true) {  if((DateTime.Now - timeLimit) > _maxSpan )  {  Debug.Write("GetTimeoutSocket timeLimit 参数有误!");  }  //从超时组 读取  List<T> result = new List<T>();  foreach(T key in _timeoutSocketGroup)  {  _timeoutSocketGroup.Add(key);  }  if(remove)  {  _timeoutSocketGroup.Clear();  }  while (_listTimeScale.Count > 0)  {  //时间轴从旧到新,查找对比  SameTimeKeyGroup<T> group = _listTimeScale[0];  if(timeLimit >= group.TimeStamp)  {   foreach (T key in group.KeyGroup)   {   result.Add(key);   if (remove)   {    _socketToSameTimeKeyGroup.Remove(key);   }   }   if(remove)   {   _listTimeScale.RemoveAt(0);   }  }  else  {   break;  }  }  return result; }

3 使用举例

//创建变量。最大超时时间为600秒,时间刻度为1秒TimeSpanManage<Socket> _deviceActiveManage = TimeSpanManage<Socket>.Create(TimeSpan.FromSeconds(600), 1000);//当有数据到达时,调用更新函数 _deviceActiveManage.UpdateTime(socket);//需要在线程或定时器中,每隔一段时间调用,找出超时的socket//找出超时时间超过600秒的socket。foreach (Socket socket in _deviceActiveManage.GetTimeoutValue(DateTime.Now.AddSeconds(-600))){ socket.Close();}

4 完整代码

/// <summary> /// 超时时间 时间间隔处理 /// </summary> class TimeSpanManage<T> { TimeSpan _maxSpan; int _minimumScaleOfMillisecond; int _scaleCount; List<SameTimeKeyGroup<T>> _listTimeScale = new List<SameTimeKeyGroup<T>>(); private TimeSpanManage() { } /// <summary> /// /// </summary> /// <param name="maxSpan">最大时间时间</param> /// <param name="minimumScaleOfMillisecond">最小刻度(毫秒)</param> /// <returns></returns> public static TimeSpanManage<T> Create(TimeSpan maxSpan, int minimumScaleOfMillisecond) {  if (minimumScaleOfMillisecond <= 0)  throw new Exception("minimumScaleOfMillisecond 小于0");  if (minimumScaleOfMillisecond > 1000)  throw new Exception("minimumScaleOfMillisecond 不能大于1000");  if (maxSpan.TotalMilliseconds <= 0)  throw new Exception("maxSpan.TotalMilliseconds 小于0");  TimeSpanManage<T> result = new TimeSpanManage<T>();  result._maxSpan = maxSpan;  result._minimumScaleOfMillisecond = minimumScaleOfMillisecond;  result._scaleCount = (int)(maxSpan.TotalMilliseconds / minimumScaleOfMillisecond);  result._scaleCount++;  return result; } Dictionary<T, SameTimeKeyGroup<T>> _socketToSameTimeKeyGroup = new Dictionary<T, SameTimeKeyGroup<T>>(); public void UpdateTime(T key) {  DateTime now = CreateNow();  //是否已存在,从上一个时间群组删除  if (_socketToSameTimeKeyGroup.ContainsKey(key))  {  SameTimeKeyGroup<T> group = _socketToSameTimeKeyGroup[key];  if (group.ContainKey(key))  {   if (group.TimeStamp == now) //同一时间更新,无需移动   {   return;   }   else   {   group.RemoveKey(key);   _socketToSameTimeKeyGroup.Remove(key);   }  }  }  //从超时组 删除  _timeoutSocketGroup.Remove(key);  //加入到新组  SameTimeKeyGroup<T> groupFromScaleList = GetOrCreateSocketGroup(now, out bool newCreate);  groupFromScaleList.AddKey(key);  _socketToSameTimeKeyGroup.Add(key, groupFromScaleList);  if (newCreate)  {  AdjustTimeout();  } } public bool RemoveSocket(T key) {  bool result = false;  if (_socketToSameTimeKeyGroup.ContainsKey(key))  {  SameTimeKeyGroup<T> group = _socketToSameTimeKeyGroup[key];  result = group.RemoveKey(key);  _socketToSameTimeKeyGroup.Remove(key);  }  //从超时组 删除  bool result2 = _timeoutSocketGroup.Remove(key);  return result || result2; } /// <summary> ///timeLimit 值为超时时刻限制 ///比如DateTime.Now.AddMilliseconds(-1000);表示 返回一秒钟以前的数据 /// </summary> /// <param name="timeLimit">该时间以前的socket会被返回</param> /// <returns></returns> public List<T> GetTimeoutValue(DateTime timeLimit, bool remove = true) {  if((DateTime.Now - timeLimit) > _maxSpan )  {  Debug.Write("GetTimeoutSocket timeLimit 参数有误!");  }  //从超时组 读取  List<T> result = new List<T>();  foreach(T key in _timeoutSocketGroup)  {  _timeoutSocketGroup.Add(key);  }  if(remove)  {  _timeoutSocketGroup.Clear();  }  while (_listTimeScale.Count > 0)  {  //时间轴从旧到新,查找对比  SameTimeKeyGroup<T> group = _listTimeScale[0];  if(timeLimit >= group.TimeStamp)  {   foreach (T key in group.KeyGroup)   {   result.Add(key);   if (remove)   {    _socketToSameTimeKeyGroup.Remove(key);   }   }   if(remove)   {   _listTimeScale.RemoveAt(0);   }  }  else  {   break;  }  }  return result; } HashSet<T> _timeoutSocketGroup = new HashSet<T>(); private void AdjustTimeout() {  while (_listTimeScale.Count > _scaleCount)  {  SameTimeKeyGroup<T> group = _listTimeScale[0];  foreach (T key in group.KeyGroup)  {   _timeoutSocketGroup.Add(key);  }  _listTimeScale.RemoveAt(0);  } } private SameTimeKeyGroup<T> GetOrCreateSocketGroup(DateTime now, out bool newCreate) {  if (_listTimeScale.Count == 0)  {  newCreate = true;  SameTimeKeyGroup<T> result = new SameTimeKeyGroup<T>(now);  _listTimeScale.Add(result);  return result;  }  else  {  SameTimeKeyGroup<T> lastGroup = _listTimeScale[_listTimeScale.Count - 1];  if (lastGroup.TimeStamp == now)  {   newCreate = false;   return lastGroup;  }  newCreate = true;  SameTimeKeyGroup<T> result = new SameTimeKeyGroup<T>(now);  _listTimeScale.Add(result);  return result;  } } DateTime CreateNow() {  DateTime now = DateTime.Now;  int m = 0;  if(now.Millisecond != 0)  {  if(_minimumScaleOfMillisecond == 1000)  {   now = now.AddSeconds(1); //尾数加1,确保超时值大于 给定的值  }  else  {   //如果now.Millisecond为16毫秒,精确度为10毫秒。则转换后为20毫秒   m = now.Millisecond - now.Millisecond % _minimumScaleOfMillisecond + _minimumScaleOfMillisecond;   if(m>=1000)   {   m -= 1000;   now = now.AddSeconds(1);   }  }  }  return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second,m); } } class SameTimeKeyGroup<T> { DateTime _timeStamp; public DateTime TimeStamp => _timeStamp; public SameTimeKeyGroup(DateTime time) {  _timeStamp = time; } public HashSet<T> KeyGroup { get; set; } = new HashSet<T>(); public bool ContainKey(T key) {  return KeyGroup.Contains(key); } internal void AddKey(T key) {  KeyGroup.Add(key); } internal bool RemoveKey(T key) {  return KeyGroup.Remove(key); } }

看完上述内容,你们掌握怎么在c#中利用socket实现一个心跳超时检测的功能的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网行业资讯频道,感谢各位的阅读!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯