最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#心跳機(jī)制服務(wù)器的示例代碼

 更新時間:2024年06月23日 09:15:47   作者:栗克  
心跳機(jī)制出現(xiàn)在tcp長連接中,客戶端和服務(wù)器之見定時發(fā)送一種特殊的數(shù)據(jù)包,本文主要介紹了C#心跳機(jī)制服務(wù)器的示例代碼,具有一定的參考價值,感興趣的可以了解一下

什么是心跳機(jī)制?
心跳機(jī)制出現(xiàn)在tcp長連接中,客戶端和服務(wù)器之見定時發(fā)送一種特殊的數(shù)據(jù)包通知對方還在線,以確保tcp鏈接地可靠性,有可能tcp鏈接由于某些原因(列入網(wǎng)線被拔了,突然斷電)導(dǎo)致客戶端斷了,但是服務(wù)器不知道客戶端斷了,服務(wù)器還保持與客戶端連接的狀態(tài),所以為了不浪費(fèi)資源,需要知道客戶端非正常中斷,服務(wù)器把斷開客戶端斷開鏈接,需要加入心跳包機(jī)制

控制臺應(yīng)用項(xiàng)目

Program.cs

internal class Program
{
    static Server server;
    static void Main(string[] args)
    {
        Server server = new Server(IPAddress.Any,3333);
        server.Start();// 除了服務(wù)器監(jiān)聽方法,監(jiān)聽客戶連接的方法,掃描客戶端是否在線的方法
        //如果監(jiān)聽到有客戶端連接的時候,打印哪個終端連入到服務(wù)器了 使用時間封裝
        server.有客戶端連入的事件 += 有客戶端連入服務(wù)器方法;// 綁定事件
        server.客戶端斷開事件 += f2;
        server.接受到消息的事件 += f3;
        Console.ReadKey();
    }
    // 相當(dāng)于點(diǎn)擊之后的毀掉方法,在客戶端連接成功之后調(diào)用這個方法
    public static void 有客戶端連入服務(wù)器方法(object obj)
    {
        TcpClient t1 = obj as TcpClient;
        Console.WriteLine(t1.Client.RemoteEndPoint+"連接到服務(wù)器");
    }
    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)建服務(wù)器對象
    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>();
    // 字段保存客戶端和當(dāng)前連接服務(wù)器時間點(diǎn)
    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();// 獲取遠(yuǎn)程ip
                // 保存當(dāng)前客戶端
                clientDic.Add(ip, client);

                // 記錄當(dāng)前客戶端心跳 鏈接成功的時候記錄當(dāng)前客戶端時間點(diǎn)
                heartDic.Add(ip, DateTime.Now);

                // 調(diào)用事件函數(shù) 觸發(fā)事件
                有客戶端連入的事件?.Invoke(client);

                // 4接受客戶端發(fā)來的消息
                ReceivMsg(client);
            }
        });
    }
    // 4 接受客戶端發(fā)來的消息
    // 封裝接受的消息
    public event Action<string> 客戶端斷開事件;// 當(dāng)客戶端斷開時候調(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的時候,當(dāng)成普通包
                    // 如果數(shù)據(jù)第一位是1說明是心跳包
                    switch (bs[0]) // 判斷第一位數(shù)據(jù)是不是0
                    {
                        case 0: // 普通數(shù)據(jù) 取出來的時候不需要顯示第一位標(biāo)識符
                            // skip 從第一位開始截取
                            // take 到指定位置的元素為止
                            // 第一位0、1代表是否心跳包標(biāo)識符
                            // 
                            byte[] body = bs.Skip(1).Take(count-1).ToArray();
                            // 要么群發(fā) 要么單發(fā)
                            接受到消息的事件?.Invoke(t1,body);
                            break;
                        case 1: // 發(fā)的是心跳包
                            // 修改是心跳包發(fā)的時間點(diǎn)
                            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 當(dāng)前時間點(diǎn)
                    // item.Value 服務(wù)器接受客戶端發(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ā)
}

到此這篇關(guān)于C#心跳機(jī)制服務(wù)器的示例代碼的文章就介紹到這了,更多相關(guān)C#心跳機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

最新評論

丹棱县| 马尔康县| 望都县| 天柱县| 营山县| 平乡县| 西青区| 若羌县| 依安县| 岳阳市| 阿拉善盟| 武陟县| 吴旗县| 浏阳市| 九江县| 四子王旗| 吉安市| 曲周县| 辰溪县| 克什克腾旗| 济宁市| 平阴县| 大埔区| 浙江省| 云龙县| 大丰市| 锦屏县| 盱眙县| 渝中区| 临汾市| 涟源市| 嘉义县| 那坡县| 桐城市| 丹棱县| 抚顺县| 西乡县| 江城| 盐源县| 双辽市| 连山|