心跳包

来源:互联网 发布:虚拟机无法桥接网络 编辑:程序博客网 时间:2024/05/13 02:43

心跳包主要用于长连接的保活和掉线处理。一般情况下为30秒。

客户端按规定时间每次发送数据给服务器端,服务器接收到之后返回一个响应给客户端,此时在客户端就能看到返回的数据,表现正常则说明连接正常。


======================================


心跳包实现思路

我们采用的思路是:客户端连接上服务端以后,服务端维护一个在线用户字典,客户端每隔一段时间,向服务器发送一个心跳包,服务器接收到包以后,字典数据的值都会更新为0;一旦服务端超过规定时间没有接收到客户端发来的包,字典数据将会递增加一,当字典数据的值累计大于等于三,则视为掉线。

代码逻辑

客户端每隔一段时间,发送一个心跳包:

复制代码
#region 心跳Timer计数事件        private void heartbeatTimer_Tick(object sender, EventArgs e)        {            currentCount++;            if (currentCount == heartbeatCount)            {                txtMessage.Append("开始发送心跳包");                MessageEntity entity = new MessageEntity();                entity.MessageType = MessagePicks.Heartbeat;                entity.NickName = loginName;                WriteToStream(entity);                currentCount = 0;            }        }        #endregion
复制代码

在服务端,会开启一个定时器,定时将userOnLineCounter中的值递增加一。如果此时收到客户端的心跳包,则将userOnLineCounter中的值重置。

复制代码
 private void heartbeatTimer_Tick(object sender, EventArgs e)        {            tickCountInStep++;            if (tickCountInStep == tickCount)            {                if (userCollection.Count > 0)                {                    //计数器自动递增                    expiryCountInStep++;                    foreach (User user in userLists)                    {                        userOnLineCounter[user]++;                    }                    //连续监测三次之后,开始监测集合中的掉线情况                    if (expiryCountInStep == expiryCount)                    {                    //寻找集合中“掉线”的用户                     var disconnectedUsers = userOnLineCounter.Where(p => p.Value >= 3).ToList();                     foreach (var disconnectedUser in disconnectedUsers)                     {                     txtLog.Append("用户" + disconnectedUser.Key.name + "掉线!");                      //删除集合中被视为掉线的用户                       userLists.Remove(disconnectedUser.Key);                       userOnLineCounter.Remove(disconnectedUser.Key);                      //开始广播发送掉线用户                     MessageEntity entity = new MessageEntity();                     entity.MessageType = MessagePicks.OffLine;                     EndPoint curOfflineUserEP = disconnectedUser.Key.client.Client.RemoteEndPoint;                     string userName = disconnectedUser.Key.name;                     entity.MessageContentEx.Add(curOfflineUserEP, userName);                    ObjectInversion inversion = new ObjectInversion();                    byte[] byteArr = inversion.SerializeTo((object)entity);                                                 try                       {                         foreach (User user in userLists)                         {                           user.writer.Write(byteArr);                           user.writer.Flush();                         }                        }                      catch { }                        }                        expiryCountInStep = 0;                    }                }                tickCountInStep = 0;            }        }    }
复制代码

收到客户端心跳包,自动重置计数器。

复制代码
case MessagePicks.Heartbeat:                    txtLog.Append("收到客户端" + entity.NickName + "的心跳回应包.");                    if (userOnLineCounter.ContainsKey(user))                        userOnLineCounter[user] = 0;                    else                        userOnLineCounter.Add(user, 0);                    break;
复制代码

效果图

(图1:三个客户端连接一个服务器)

(图2:用户“上善若水”掉线)

(图3:用户“古道热肠”掉线)

 程序暂时还未完全完成,有需要的可以参考下。当然也期待大家的各种思路。

代码很丑,期望大家指点下重构的方法。

源码下载

点击这里下载

=====================2014年9月24日重构版本=======================

用户实体内部通过维护一个timer计数器,实现心跳检测,心跳超时功能。

点击这里下载新版