您的位置:首页 > 理论基础 > 计算机网络

socket心跳超时检测,快速处理新思路(适用于超大量TCP连接情况下)

2018-11-14 11:30 691 查看

假设一种情景:TCP服务器有1万个客户端连接,如果客户端5秒钟不发数据,则要断开。服务端如何检测客户端是否超时?这看起来是一个非常简单的问题,其实不然!

最简单的处理方法是:启动一个线程,每隔一段时间,检查每个连接是否超时。每次处理需要1万次检查。计算量太大!检查的时间间隔不能太小,否则大大增加计算量;如果间隔时间太大,超时误差会增大。

本文提出一种新颖的处理方法,就是针对这个看似简单而不易解决的问题!(以下用socket表示一个客户端连接)

 1 内存布局图

  

1   /// <summary>
2     /// 超时时间 时间间隔处理
3     /// </summary>
4     class TimeSpanManage<T>
5     {
6         TimeSpan _maxSpan;
7         int _minimumScaleOfMillisecond;
8         int _scaleCount;
9
10         List<SameTimeKeyGroup<T>> _listTimeScale = new List<SameTimeKeyGroup<T>>();
11         private TimeSpanManage()
12         {
13         }
14
15         /// <summary>
16         ///
17         /// </summary>
18         /// <param name="maxSpan">最大时间时间</param>
19         /// <param name="minimumScaleOfMillisecond">最小刻度(毫秒)</param>
20         /// <returns></returns>
21         public static TimeSpanManage<T> Create(TimeSpan maxSpan, int minimumScaleOfMillisecond)
22         {
23             if (minimumScaleOfMillisecond <= 0)
24                 throw new Exception("minimumScaleOfMillisecond 小于0");
25             if (minimumScaleOfMillisecond > 1000)
26                 throw new Exception("minimumScaleOfMillisecond 不能大于1000");
27
28             if (maxSpan.TotalMilliseconds <= 0)
29                 throw new Exception("maxSpan.TotalMilliseconds 小于0");
30
31             TimeSpanManage<T> result = new TimeSpanManage<T>();
32             result._maxSpan = maxSpan;
33             result._minimumScaleOfMillisecond = minimumScaleOfMillisecond;
34
35             result._scaleCount = (int)(maxSpan.TotalMilliseconds / minimumScaleOfMillisecond);
36             result._scaleCount++;
37             return result;
38         }
39
40         Dictionary<T, SameTimeKeyGroup<T>> _socketToSameTimeKeyGroup = new Dictionary<T, SameTimeKeyGroup<T>>();
41         public void UpdateTime(T key)
42         {
43             DateTime now = CreateNow();
44             //是否已存在,从上一个时间群组删除
45             if (_socketToSameTimeKeyGroup.ContainsKey(key))
46             {
47                 SameTimeKeyGroup<T> group = _socketToSameTimeKeyGroup[key];
48                 if (group.ContainKey(key))
49                 {
50                     if (group.TimeStamp == now) //同一时间更新,无需移动
51                     {
52                         return;
53                     }
54                     else
55                     {
56                         group.RemoveKey(key);
57                         _socketToSameTimeKeyGroup.Remove(key);
58                     }
59                 }
60             }
61
62             //从超时组 删除
63             _timeoutSocketGroup.Remove(key);
64
65             //加入到新组
66             SameTimeKeyGroup<T> groupFromScaleList = GetOrCreateSocketGroup(now, out bool newCreate);
67             groupFromScaleList.AddKey(key);
68
69             _socketToSameTimeKeyGroup.Add(key, groupFromScaleList);
70
71             if (newCreate)
72             {
73                 AdjustTimeout();
74             }
75         }
76
77         public bool RemoveSocket(T key)
78         {
79             bool result = false;
80             if (_socketToSameTimeKeyGroup.ContainsKey(key))
81             {
82                 SameTimeKeyGroup<T> group = _socketToSameTimeKeyGroup[key];
83                 result = group.RemoveKey(key);
84
85                 _socketToSameTimeKeyGroup.Remove(key);
86             }
87
88             //从超时组 删除
89             bool result2 = _timeoutSocketGroup.Remove(key);
90             return result || result2;
91         }
92
93         /// <summary>
94         ///timeLimit 值为超时时刻限制
95         ///比如DateTime.Now.AddMilliseconds(-1000);表示 返回一秒钟以前的数据
96         /// </summary>
97         /// <param name="timeLimit">该时间以前的socket会被返回</param>
98         /// <returns></returns>
99         public List<T> GetTimeoutValue(DateTime timeLimit, bool remove = true)
100         {
101             if((DateTime.Now - timeLimit) > _maxSpan )
102             {
103                 Debug.Write("GetTimeoutSocket timeLimit 参数有误!");
104             }
105
106             //从超时组 读取
107             List<T> result = new List<T>();
108             foreach(T key in _timeoutSocketGroup)
109             {
110                 _timeoutSocketGroup.Add(key);
111             }
112
113             if(remove)
114             {
115                 _timeoutSocketGroup.Clear();
116             }
117
118             while (_listTimeScale.Count > 0)
119             {
120                 //时间轴从旧到新,查找对比
121                 SameTimeKeyGroup<T> group = _listTimeScale[0];
122                 if(timeLimit >= group.TimeStamp)
123                 {
124                     foreach (T key in group.KeyGroup)
125                     {
126                         result.Add(key);
127                         if (remove)
128                         {
129                             _socketToSameTimeKeyGroup.Remove(key);
130                         }
131                     }
132
133                     if(remove)
134                     {
135                         _listTimeScale.RemoveAt(0);
136                     }
137                 }
138                 else
139                 {
140                     break;
141                 }
142             }
143
144             return result;
145         }
146
147         HashSet<T> _timeoutSocketGroup = new HashSet<T>();
148         private void AdjustTimeout()
149         {
150             while (_listTimeScale.Count > _scaleCount)
151             {
152                 SameTimeKeyGroup<T> group = _listTimeScale[0];
153                 foreach (T key in group.KeyGroup)
154                 {
155                     _timeoutSocketGroup.Add(key);
156                 }
157
158                 _listTimeScale.RemoveAt(0);
159             }
160         }
161
162         private SameTimeKeyGroup<T> GetOrCreateSocketGroup(DateTime now, out bool newCreate)
163         {
164             if (_listTimeScale.Count == 0)
165             {
166                 newCreate = true;
167                 SameTimeKeyGroup<T> result = new SameTimeKeyGroup<T>(now);
168                 _listTimeScale.Add(result);
169                 return result;
170             }
171             else
172             {
173                 SameTimeKeyGroup<T> lastGroup = _listTimeScale[_listTimeScale.Count - 1];
174                 if (lastGroup.TimeStamp == now)
175                 {
176                     newCreate = false;
177                     return lastGroup;
178                 }
179
180                 newCreate = true;
181                 SameTimeKeyGroup<T> result = new SameTimeKeyGroup<T>(now);
182                 _listTimeScale.Add(result);
183                 return result;
184             }
185         }
186
187         DateTime CreateNow()
188         {
189             DateTime now = DateTime.Now;
190             int m = 0;
191             if(now.Millisecond != 0)
192             {
193                 if(_minimumScaleOfMillisecond == 1000)
194                 {
195                     now = now.AddSeconds(1); //尾数加1,确保超时值大于 给定的值
196                 }
197                 else
198                 {
199                     //如果now.Millisecond为16毫秒,精确度为10毫秒。则转换后为20毫秒
200                     m = now.Millisecond - now.Millisecond % _minimumScaleOfMillisecond + _minimumScaleOfMillisecond;
201                     if(m>=1000)
202                     {
203                         m -= 1000;
204                         now = now.AddSeconds(1);
205                     }
206                 }
207             }
208             return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second,m);
209         }
210     }
211
212     class SameTimeKeyGroup<T>
213     {
214         DateTime _timeStamp;
215         public DateTime TimeStamp => _timeStamp;
216         public SameTimeKeyGroup(DateTime time)
217         {
218             _timeStamp = time;
219         }
220         public HashSet<T> KeyGroup { get; set; } = new HashSet<T>();
221
222         public bool ContainKey(T key)
223         {
224             return KeyGroup.Contains(key);
225         }
226
227         internal void AddKey(T key)
228         {
229             KeyGroup.Add(key);
230         }
231         internal bool RemoveKey(T key)
232         {
233            return  KeyGroup.Remove(key);
234         }
235     }
View Code  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: