C#心跳機制服務器的示例代碼
什么是心跳機制?
心跳機制出現(xiàn)在tcp長連接中,客戶端和服務器之見定時發(fā)送一種特殊的數(shù)據(jù)包通知對方還在線,以確保tcp鏈接地可靠性,有可能tcp鏈接由于某些原因(列入網(wǎng)線被拔了,突然斷電)導致客戶端斷了,但是服務器不知道客戶端斷了,服務器還保持與客戶端連接的狀態(tài),所以為了不浪費資源,需要知道客戶端非正常中斷,服務器把斷開客戶端斷開鏈接,需要加入心跳包機制
控制臺應用項目
Program.cs
internal class Program { static Server server; static void Main(string[] args) { Server server = new Server(IPAddress.Any,3333); server.Start();// 除了服務器監(jiān)聽方法,監(jiān)聽客戶連接的方法,掃描客戶端是否在線的方法 //如果監(jiān)聽到有客戶端連接的時候,打印哪個終端連入到服務器了 使用時間封裝 server.有客戶端連入的事件 += 有客戶端連入服務器方法;// 綁定事件 server.客戶端斷開事件 += f2; server.接受到消息的事件 += f3; Console.ReadKey(); } // 相當于點擊之后的毀掉方法,在客戶端連接成功之后調(diào)用這個方法 public static void 有客戶端連入服務器方法(object obj) { TcpClient t1 = obj as TcpClient; Console.WriteLine(t1.Client.RemoteEndPoint+"連接到服務器"); } public static void f2(object obj) { Console.WriteLine(obj.ToString()+"斷開連接"); } public static void f3(TcpClient t1, byte[] b1) { t1.GetStream().Write(b1, 0, b1.Length); } }
Server.cs
internal class Server { TcpListener listen; // 1 通過構(gòu)造函數(shù)創(chuàng)建服務器對象 public Server(IPAddress ip,int port) { listen = new TcpListener(ip, port); } // 2 封裝開啟監(jiān)聽的方法 public void Start() { listen.Start(100);// 開啟監(jiān)聽 // 接受客戶端的連接 StartConnect(); // 掃描心跳方法 SaoMiao(); } // 3 接受客戶端的連接 封裝一監(jiān)聽客戶端連接的方法 // 保存所有的客戶端字典,鍵是ip 值是客戶端 Dictionary<string, TcpClient> clientDic = new Dictionary<string, TcpClient>(); // 字段保存客戶端和當前連接服務器時間點 Dictionary<string, DateTime> heartDic = new Dictionary<string, DateTime>(); public event Action<TcpClient> 有客戶端連入的事件; void StartConnect() { Task.Run(() => { while (true)// 接入多個客戶端 { TcpClient client = listen.AcceptTcpClient(); string ip = client.Client.RemoteEndPoint.ToString();// 獲取遠程ip // 保存當前客戶端 clientDic.Add(ip, client); // 記錄當前客戶端心跳 鏈接成功的時候記錄當前客戶端時間點 heartDic.Add(ip, DateTime.Now); // 調(diào)用事件函數(shù) 觸發(fā)事件 有客戶端連入的事件?.Invoke(client); // 4接受客戶端發(fā)來的消息 ReceivMsg(client); } }); } // 4 接受客戶端發(fā)來的消息 // 封裝接受的消息 public event Action<string> 客戶端斷開事件;// 當客戶端斷開時候調(diào)用 public event Action<TcpClient, byte[]> 接受到消息的事件;// 接收到消息調(diào)用 void ReceivMsg(TcpClient t1) { NetworkStream stream = t1.GetStream(); string ip = t1.Client.RemoteEndPoint.ToString(); byte[] bs = new byte[1024]; Task.Run(() => { try { while (true) { int count = stream.Read(bs, 0, bs.Length); // 必須判斷是否是心跳包 事先約定好 if (count == 0) { // 客戶端斷開 throw new Exception("客戶端斷開連接"); } // 如果接收數(shù)據(jù)長度不為0 // 必須判斷是否心跳包 事先約定好:如果數(shù)據(jù)第一位是0的時候,當成普通包 // 如果數(shù)據(jù)第一位是1說明是心跳包 switch (bs[0]) // 判斷第一位數(shù)據(jù)是不是0 { case 0: // 普通數(shù)據(jù) 取出來的時候不需要顯示第一位標識符 // skip 從第一位開始截取 // take 到指定位置的元素為止 // 第一位0、1代表是否心跳包標識符 // byte[] body = bs.Skip(1).Take(count-1).ToArray(); // 要么群發(fā) 要么單發(fā) 接受到消息的事件?.Invoke(t1,body); break; case 1: // 發(fā)的是心跳包 // 修改是心跳包發(fā)的時間點 heartDic[ip] = DateTime.Now; break; } } } catch (Exception e) { // 從字典里把客戶端清除掉 clientDic.Remove(ip); // 如果客戶端打開了,打印客戶 客戶端斷開事件?.Invoke(ip); //刪除心跳記錄 heartDic.Remove(ip); } }); } // 遍歷所有客戶端 掃描是否在未超時時間內(nèi) void SaoMiao() { Task.Run(() => { while (true) { Thread.Sleep(4000);// 線程休眠4s DateTime now1 = DateTime.Now; foreach (var item in heartDic) // 遍歷所以的心跳記錄 { // now1 當前時間點 // item.Value 服務器接受客戶端發(fā)來的心跳包時間 if (now1-item.Value>new TimeSpan(0,0,4)) { Console.WriteLine(item.Key+"掉線了"); } else { Console.WriteLine(item.Key+"在線"); } } } }); } // 無參數(shù)的構(gòu)造函數(shù) public Server() { } // 群發(fā)方法 public void Send() { } // 指定給誰發(fā) public void send指定() { } //指定給哪些客戶端發(fā) }
到此這篇關于C#心跳機制服務器的示例代碼的文章就介紹到這了,更多相關C#心跳機制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
js substr,substring與java substring和C# substring的區(qū)別解析
本篇文章主要是對js中substr,substring與java中substring和C#中substring的區(qū)別進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助2014-01-01C#中DataTable實現(xiàn)行列轉(zhuǎn)換的方法
這篇文章主要介紹了C#中DataTable實現(xiàn)行列轉(zhuǎn)換的方法,實例分析了C#操作DataTable的相關技巧,非常具有實用價值,需要的朋友可以參考下2015-04-04C#調(diào)用Python程序傳參數(shù)獲得返回值
C# 調(diào)用 Python 程序有多種方式,本文主要介紹了4種方式,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02