TCP之心跳包實現思路

提及網絡應用編程,想到最多的就是聊天類的軟件。固然,在這類軟件中,通常都會有一個用戶掉線檢測功能。今天咱們就經過使用自定義的HeartBeat方式來檢測用戶的掉線狀況。編程

心跳包實現思路服務器

咱們採用的思路是:客戶端鏈接上服務端之後,服務端維護一個在線用戶字典,客戶端每隔一段時間,向服務器發送一個心跳包,服務器接收到包之後,字典數據的值都會更新爲0;一旦服務端超過規定時間沒有接收到客戶端發來的包,字典數據將會遞增長一,當字典數據的值累計大於等於三,則視爲掉線。網絡

代碼邏輯less

客戶端每隔一段時間,發送一個心跳包:ide

#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
View Code

在服務端,會開啓一個定時器,定時將userOnLineCounter中的值遞增長一。若是此時收到客戶端的心跳包,則將userOnLineCounter中的值重置。spa

 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;
            }
        }
    }
View Code

收到客戶端心跳包,自動重置計數器。3d

case MessagePicks.Heartbeat:
                    txtLog.Append("收到客戶端" + entity.NickName + "的心跳回應包.");
                    if (userOnLineCounter.ContainsKey(user))
                        userOnLineCounter[user] = 0;
                    else
                        userOnLineCounter.Add(user, 0);
                    break;
View Code

效果圖code

(圖1:三個客戶端鏈接一個服務器)blog

(圖2:用戶「上善若水」掉線)事件

(圖3:用戶「古道熱腸」掉線)

 程序暫時還未徹底完成,有須要的能夠參考下。固然也期待你們的各類思路。

代碼很醜,指望你們指點下重構的方法。

源碼下載

點擊這裏下載

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

用戶實體內部經過維護一個timer計數器,實現心跳檢測,心跳超時功能。

點擊這裏下載新版

相關文章
相關標籤/搜索