说起网络应用编程,想到最多的就是聊天类的软件。当然,在这类软件中,一般都会有一个用户掉线检测功能。今天我们就通过使用自定义的HeartBeat方式来检测用户的掉线情况。

心跳包实现思路

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

                

易语言mysql设置心跳 易语言心跳包教程_易语言mysql设置心跳

代码逻辑

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

#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;

效果图

易语言mysql设置心跳 易语言心跳包教程_心跳包_02

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

 

易语言mysql设置心跳 易语言心跳包教程_易语言mysql设置心跳_03

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

易语言mysql设置心跳 易语言心跳包教程_服务端_04

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

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

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