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

C# 實(shí)現(xiàn)Scoket心跳機(jī)制的方法

 更新時(shí)間:2020年02月12日 11:36:29   作者:PassionY  
這篇文章主要介紹了C# 實(shí)現(xiàn)Scoket心跳機(jī)制的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

TCP網(wǎng)絡(luò)長連接

手機(jī)能夠使用聯(lián)網(wǎng)功能是因?yàn)槭謾C(jī)底層實(shí)現(xiàn)了TCP/IP協(xié)議,可以使手機(jī)終端通過無線網(wǎng)絡(luò)建立TCP連接。TCP協(xié)議可以對上層網(wǎng)絡(luò)提供接口,使上層網(wǎng)絡(luò)數(shù)據(jù)的傳輸建立在“無差別”的網(wǎng)絡(luò)之上。

建立起一個(gè)TCP連接需要經(jīng)過“三次握手”:
第一次握手:客戶端發(fā)送syn包(syn=j)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn);
第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手。

握手過程中傳送的包里不包含數(shù)據(jù),三次握手完畢后,客戶端與服務(wù)器才正式開始傳送數(shù)據(jù)。理想狀態(tài)下,TCP連接一旦建立,在通信雙方中的任何一方主動關(guān)閉連接之前,TCP 連接都將被一直保持下去。斷開連接時(shí)服務(wù)器和客戶端均可以主動發(fā)起斷開TCP連接的請求,斷開過程需要經(jīng)過“四次握手”(過程就不細(xì)寫了,就是服務(wù)器和客戶端交互,最終確定斷開)

什么是心跳

剛才說到長連接建立連接后,理想狀態(tài)下是不會斷開的,但是由于網(wǎng)絡(luò)問題,可能導(dǎo)致一方斷開后,另一方仍然在發(fā)送數(shù)據(jù),或者有些客戶端長時(shí)間不發(fā)送消息,服務(wù)器還維持這他的客戶端不必要的引用,增加了服務(wù)器的負(fù)荷。因此我們引入了心跳機(jī)制。

心跳包之所以叫心跳包是因?yàn)椋核裥奶粯用扛艄潭〞r(shí)間發(fā)一次,以此來告訴服務(wù)器,這個(gè)客戶端還活著。事實(shí)上這是為了保持長連接,至于這個(gè)包的內(nèi)容,是沒有什么特別規(guī)定的,不過一般都是很小的包,或者只包含包頭的一個(gè)空包。

總的來說,心跳包主要也就是用于長連接的?;詈蛿嗑€處理。一般的應(yīng)用下,判定時(shí)間在30-40秒比較不錯。如果實(shí)在要求高,那就在6-9秒。

怎么發(fā)送心跳?

心跳包的發(fā)送,通常有兩種技術(shù)

方法1:應(yīng)用層自己實(shí)現(xiàn)的心跳包 

由應(yīng)用程序自己發(fā)送心跳包來檢測連接是否正常,大致的方法是:服務(wù)器在一個(gè) Timer事件中定時(shí) 向客戶端發(fā)送一個(gè)短小精悍的數(shù)據(jù)包,然后啟動一個(gè)低級別的線程,在該線程中不斷檢測客戶端的回應(yīng), 如果在一定時(shí)間內(nèi)沒有收到客戶端的回應(yīng),即認(rèn)為客戶端已經(jīng)掉線;同樣,如果客戶端在一定時(shí)間內(nèi)沒 有收到服務(wù)器的心跳包,則認(rèn)為連接不可用。

方法2:TCP的KeepAlive?;顧C(jī)制

因?yàn)橐紤]到一個(gè)服務(wù)器通常會連接多個(gè)客戶端,因此由用戶在應(yīng)用層自己實(shí)現(xiàn)心跳包,代碼較多 且稍顯復(fù)雜,而利用TCP/IP協(xié)議層為內(nèi)置的KeepAlive功能來實(shí)現(xiàn)心跳功能則簡單得多。 不論是服務(wù)端還是客戶端,一方開啟KeepAlive功能后,就會自動在規(guī)定時(shí)間內(nèi)向?qū)Ψ桨l(fā)送心跳包, 而另一方在收到心跳包后就會自動回復(fù),以告訴對方我仍然在線。 因?yàn)殚_啟KeepAlive功能需要消耗額外的寬帶和流量,所以TCP協(xié)議層默認(rèn)并不開啟KeepAlive功 能,盡管這微不足道,但在按流量計(jì)費(fèi)的環(huán)境下增加了費(fèi)用,另一方面,KeepAlive設(shè)置不合理時(shí)可能會 因?yàn)槎虝旱木W(wǎng)絡(luò)波動而斷開健康的TCP連接。并且,默認(rèn)的KeepAlive超時(shí)需要7,200,000 MilliSeconds, 即2小時(shí),探測次數(shù)為5次。對于很多服務(wù)端應(yīng)用程序來說,2小時(shí)的空閑時(shí)間太長。因此,我們需要手工開啟KeepAlive功能并設(shè)置合理的KeepAlive參數(shù)。

心跳檢測步驟:

1客戶端每隔一個(gè)時(shí)間間隔發(fā)生一個(gè)探測包給服務(wù)器
2客戶端發(fā)包時(shí)啟動一個(gè)超時(shí)定時(shí)器
3服務(wù)器端接收到檢測包,應(yīng)該回應(yīng)一個(gè)包
4如果客戶機(jī)收到服務(wù)器的應(yīng)答包,則說明服務(wù)器正常,刪除超時(shí)定時(shí)器
5如果客戶端的超時(shí)定時(shí)器超時(shí),依然沒有收到應(yīng)答包,則說明服務(wù)器掛了

C#實(shí)現(xiàn)的一個(gè)簡單的心跳

using System;
using System.Collections.Generic;
using System.Threading;
 
namespace ConsoleApplication1
{
  // 客戶端離線委托
  public delegate void ClientOfflineHandler(ClientInfo client);
 
  // 客戶端上線委托
  public delegate void ClientOnlineHandler(ClientInfo client);
 
  public class Program
  {
    /// <summary>
    /// 客戶端離線提示
    /// </summary>
    /// <param name="clientInfo"></param>
    private static void ClientOffline(ClientInfo clientInfo)
    {
      Console.WriteLine(String.Format("客戶端{(lán)0}離線,離線時(shí)間:\t{1}", clientInfo.ClientID, clientInfo.LastHeartbeatTime));
    }
 
    /// <summary>
    /// 客戶端上線提示
    /// </summary>
    /// <param name="clientInfo"></param>
    private static void ClientOnline(ClientInfo clientInfo)
    {
      Console.WriteLine(String.Format("客戶端{(lán)0}上線,上線時(shí)間:\t{1}", clientInfo.ClientID, clientInfo.LastHeartbeatTime));
    }
 
    static void Main()
    {
      // 服務(wù)端
      Server server = new Server();
 
      // 服務(wù)端離線事件
      server.OnClientOffline += ClientOffline;
 
      // 服務(wù)器上線事件
      server.OnClientOnline += ClientOnline;
 
      // 開啟服務(wù)器
      server.Start();
 
      // 模擬100個(gè)客戶端
      Dictionary<Int32, Client> dicClient = new Dictionary<Int32, Client>();
      for (Int32 i = 0; i < 100; i++)
      {
        // 這里傳入server只是為了方便而已
        Client client = new Client(i + 1, server);
        dicClient.Add(i + 1, client);
 
        // 開啟客戶端
        client.Start();
      }
 
      System.Threading.Thread.Sleep(1000);
 
      while (true)
      {
        Console.WriteLine("請輸入要離線的ClientID,輸入0則退出程序:");
        String clientID = Console.ReadLine();
        if (!String.IsNullOrEmpty(clientID))
        {
          Int32 iClientID = 0;
          Int32.TryParse(clientID, out iClientID);
          if (iClientID > 0)
          {
            Client client;
            if (dicClient.TryGetValue(iClientID, out client))
            {
              // 客戶端離線
              client.Offline = true;
            }
          }
          else
          {
            return;
          }
        }
      }
    }
  }
 
  /// <summary>
  /// 服務(wù)端
  /// </summary>
  public class Server
  {
    public event ClientOfflineHandler OnClientOffline;
    public event ClientOnlineHandler OnClientOnline;
 
    private Dictionary<Int32, ClientInfo> _DicClient;
 
    /// <summary>
    /// 構(gòu)造函數(shù)
    /// </summary>
    public Server()
    {
      _DicClient = new Dictionary<Int32, ClientInfo>(100);      
    }
 
    /// <summary>
    /// 開啟服務(wù)端
    /// </summary>
    public void Start()
    {
      // 開啟掃描離線線程
      Thread t = new Thread(new ThreadStart(ScanOffline));
      t.IsBackground = true;
      t.Start();
    }
 
    /// <summary>
    /// 掃描離線
    /// </summary>
    private void ScanOffline()
    {
      while (true)
      {
        // 一秒掃描一次
        System.Threading.Thread.Sleep(1000);
 
        lock (_DicClient)
        {
          foreach (Int32 clientID in _DicClient.Keys)
          {
            ClientInfo clientInfo = _DicClient[clientID];
 
            // 如果已經(jīng)離線則不用管
            if (!clientInfo.State)
            {
              continue;
            }
 
            // 判斷最后心跳時(shí)間是否大于3秒
            TimeSpan sp = System.DateTime.Now - clientInfo.LastHeartbeatTime;
            if (sp.Seconds >= 3)
            {
              // 離線,觸發(fā)離線事件
              if (OnClientOffline != null)
              {
                OnClientOffline(clientInfo);
              }
 
              // 修改狀態(tài)
              clientInfo.State = false;
            }
          }
        }
      }
    }
 
    /// <summary>
    /// 接收心跳包
    /// </summary>
    /// <param name="clientID">客戶端ID</param>
    public void ReceiveHeartbeat(Int32 clientID)
    {
      lock (_DicClient)
      {
        ClientInfo clientInfo;
        if (_DicClient.TryGetValue(clientID, out clientInfo))
        {
          // 如果客戶端已經(jīng)上線,則更新最后心跳時(shí)間
          clientInfo.LastHeartbeatTime = System.DateTime.Now;
        }
        else
        {
          // 客戶端不存在,則認(rèn)為是新上線的
          clientInfo = new ClientInfo();
          clientInfo.ClientID = clientID;
          clientInfo.LastHeartbeatTime = System.DateTime.Now;
          clientInfo.State = true;
 
          _DicClient.Add(clientID, clientInfo);
 
          // 觸發(fā)上線事件
          if (OnClientOnline != null)
          {
            OnClientOnline(clientInfo);
          }
        }
      }
    }
  }
 
  /// <summary>
  /// 客戶端
  /// </summary>
  public class Client
  {
    public Server Server;
    public Int32 ClientID;
    public Boolean Offline;
 
    /// <summary>
    /// 構(gòu)造函數(shù)
    /// </summary>
    /// <param name="clientID"></param>
    /// <param name="server"></param>
    public Client(Int32 clientID, Server server)
    {
      ClientID = clientID;
      Server = server;
      Offline = false;
    }
 
    /// <summary>
    /// 開啟客戶端
    /// </summary>
    public void Start()
    {
      // 開啟心跳線程
      Thread t = new Thread(new ThreadStart(Heartbeat));
      t.IsBackground = true;
      t.Start();
    }
 
    /// <summary>
    /// 向服務(wù)器發(fā)送心跳包
    /// </summary>
    private void Heartbeat()
    {
      while (!Offline)
      {
        // 向服務(wù)端發(fā)送心跳包
        Server.ReceiveHeartbeat(ClientID);
         
        System.Threading.Thread.Sleep(1000);
      }
    }
  }
 
  /// <summary>
  /// 客戶端信息
  /// </summary>
  public class ClientInfo
  {
    // 客戶端ID
    public Int32 ClientID;
 
    // 最后心跳時(shí)間
    public DateTime LastHeartbeatTime;
 
    // 狀態(tài)
    public Boolean State;
  }
}

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C#泛型設(shè)計(jì)需要注意的一個(gè)小陷阱

    C#泛型設(shè)計(jì)需要注意的一個(gè)小陷阱

    這篇文章主要給大家介紹了關(guān)于C#泛型設(shè)計(jì)需要注意的一個(gè)小陷阱,文中通過示例代碼以及圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 淺談C#數(shù)組(一)

    淺談C#數(shù)組(一)

    本篇文章小編要得大家介紹的是C#數(shù)組,數(shù)組是一種數(shù)據(jù)結(jié)構(gòu),它可以包含同一個(gè)類型的多個(gè)元素,如果需要使用同一類型的多個(gè)對象,可以使用數(shù)組和集合,需要的朋友可以參考下面文章的具體內(nèi)容
    2021-09-09
  • 詳解C#如何使用讀寫鎖控制多線程寫入

    詳解C#如何使用讀寫鎖控制多線程寫入

    這篇文章主要為大家詳細(xì)介紹了C#如何使用讀寫鎖控制多線程寫入,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • C# 如何實(shí)現(xiàn)一個(gè)基于值相等性比較的字典

    C# 如何實(shí)現(xiàn)一個(gè)基于值相等性比較的字典

    這篇文章主要介紹了C# 如何實(shí)現(xiàn)一個(gè)基于值相等性比較的字典,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2021-02-02
  • C#中32位浮點(diǎn)數(shù)Float(Real)一步步按位Bit進(jìn)行分析

    C#中32位浮點(diǎn)數(shù)Float(Real)一步步按位Bit進(jìn)行分析

    這篇文章主要介紹了C#中32位浮點(diǎn)數(shù)Float(Real)一步步按位Bit進(jìn)行分析,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • WPF實(shí)現(xiàn)窗體亞克力效果的示例代碼

    WPF實(shí)現(xiàn)窗體亞克力效果的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用WPF實(shí)現(xiàn)窗體亞克力效果,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)或工作有一定幫助,感興趣的小伙伴可以了解一下
    2022-10-10
  • c# 適配器模式

    c# 適配器模式

    適配器模式:將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另一個(gè)接口,Adapter使原本由于接口不兼容而不能一起工作的那些類可以一起工作
    2012-10-10
  • C#實(shí)現(xiàn)可緩存網(wǎng)頁到本地的反向代理工具實(shí)例

    C#實(shí)現(xiàn)可緩存網(wǎng)頁到本地的反向代理工具實(shí)例

    這篇文章主要介紹了C#實(shí)現(xiàn)可緩存網(wǎng)頁到本地的反向代理工具,實(shí)例分析了C#實(shí)現(xiàn)反向代理的相關(guān)技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-04-04
  • C#?HttpClient超時(shí)重試機(jī)制詳解

    C#?HttpClient超時(shí)重試機(jī)制詳解

    超時(shí)重試的實(shí)現(xiàn)方式可以使用循環(huán)結(jié)構(gòu),在請求發(fā)起后等待一定時(shí)間,若超時(shí)未收到響應(yīng),則再次發(fā)起請求,循環(huán)次數(shù)可以根據(jù)實(shí)際情況進(jìn)行設(shè)置,一般建議不超過三次,這篇文章主要介紹了C#?HttpClient超時(shí)重試,需要的朋友可以參考下
    2023-06-06
  • C#在Windows上調(diào)用7-zip實(shí)現(xiàn)壓縮文件

    C#在Windows上調(diào)用7-zip實(shí)現(xiàn)壓縮文件

    這篇文章主要為大家詳細(xì)介紹了C#如何在Windows上調(diào)用7-zip實(shí)現(xiàn)壓縮文件,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以學(xué)習(xí)一下
    2023-10-10

最新評論

醴陵市| 南溪县| 陇西县| 贵德县| 三明市| 衡山县| 砀山县| 铜山县| 电白县| 武陟县| 德钦县| 广南县| 高密市| 嘉鱼县| 安仁县| 巧家县| 新野县| 西畴县| 古蔺县| 长丰县| 沽源县| 县级市| 民丰县| 井研县| 海安县| 新乐市| 耒阳市| 马边| 沁水县| 渭源县| 马山县| 蕉岭县| 三门峡市| 常宁市| 西藏| 响水县| 赤水市| 宁河县| 石城县| 涟源市| 陆河县|