說起網絡應用編程,想到最多的就是聊天類的軟件。當然,在這類軟件中,一般都會有一個用戶掉線檢測功能。今天我們就通過使用自定義的HeartBeat方式來檢測用戶的掉線情況。
心跳包實現思路
我們采用的思路是:客戶端連接上服務端以后,服務端維護一個在線用戶字典,客戶端每隔一段時間,向服務器發送一個心跳包,服務器接收到包以后,字典數據的值都會更新為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計數器,實現心跳檢測,心跳超時功能。