【問題記錄】—SignalR連線斷線重連

chaney1992發表於2021-06-13

起因:

 ASP.NET Core SignalR是一個開源庫,可簡化嚮應用新增實時 SignalR Web 功能。 實時 Web 功能使伺服器端程式碼能夠立即將內容推送到客戶端。(相信大家都用得比較多了)

 在應用過程中,出現某些異常斷開連線情況,那麼如何處理客戶端自動重連呢?

問題現象:

 伺服器因某些特殊原因,導致服務停止一段時間後;當服務端重啟後,Signalr連線的客戶端未能自動連線到服務上。

解決辦法:

  實現自動斷線重連的2種方式:

  • 在onClose事件中手動重新建立連線:
connection.Closed += async (error) =>
{
    //等待3s後重新建立連線
    await Task.Delay(3* 1000);
    await connection.StartAsync();
};
  • 將配置為使用方法 WithAutomaticReconnect 自動重新連線

  重連規則:

如果客戶端在其指定次數嘗試內成功重新連線,則 HubConnection 將轉換回 Connected 狀態並激發 Reconnected 事件。 這為使用者提供了通知使用者已重新建立連線並取消排隊訊息的排隊的機會。

如果客戶端在其指定次數嘗試中未成功重新連線,則 HubConnection 將轉換為 Disconnected 狀態並觸發 Closed 事件。 這為嘗試手動重新啟動連線或通知使用者連線永久丟失有機會。

  1、WithAutomaticReconnect在沒有任何引數的情況下, 將客戶端配置為分別等待0、2、10 和 30 秒,然後嘗試每次重新連線嘗試,在四次嘗試失敗後停止。出發Closed事件

HubConnectionBuilder hubConnectionBuilder = new HubConnectionBuilder();
hubConnectionBuilder.WithUrl(url, options => { });
//重連
hubConnectionBuilder = (HubConnectionBuilder)hubConnectionBuilder
    .WithAutomaticReconnect();
//建立連線物件
hubConnection = hubConnectionBuilder.Build();
//斷開連線
hubConnection.Closed += HubConnection_Closed;
//重連中
hubConnection.Reconnecting += HubConnection_Reconnecting;
//重連成功
hubConnection.Reconnected += HubConnection_Reconnected;
//心跳檢查
hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(60);

  2、指定斷線重連引數:連線規則同上(次數變成指定的3次)

//指定重連間隔:0s,0s,10s
HubConnection connection= new HubConnectionBuilder() .WithUrl(new Uri("http://127.0.0.1:5000/chathub")) .WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10) }) .Build();

  3、自定義重連規則使用:實現一直自動重連

HubConnectionBuilder hubConnectionBuilder = new HubConnectionBuilder();
hubConnectionBuilder.WithUrl(url, options => { });
//自定義重連規則實現
hubConnectionBuilder = (HubConnectionBuilder)hubConnectionBuilder
    .WithAutomaticReconnect(new RetryPolicy());

  重連規則實現:重連規則:重試次數<50:間隔1s;重試次數<250:間隔30s;重試次數>250:間隔1m

//實現IRetryPolicy介面
class RetryPolicy : IRetryPolicy
{
    /// <summary>
    /// 重連規則:重連次數<50:間隔1s;重試次數<250:間隔30s;重試次數>250:間隔1m
    /// </summary>
    /// <param name="retryContext"></param>
    /// <returns></returns>
    public TimeSpan? NextRetryDelay(RetryContext retryContext)
    {
        var count = retryContext.PreviousRetryCount / 50;
        if (count < 1)//重試次數<50,間隔1s
        {
            return new TimeSpan(0, 0, 1);
        }
        else if (count < 5)//重試次數<250:間隔30s
        {
            return new TimeSpan(0, 0, 30);
        }
        else //重試次數>250:間隔1m
        {
            return new TimeSpan(0, 1, 0);
        }
    }
} 

其他常見用法:

 1、服務端/客戶端配置:

  a)Json序列化屬性名不修改大小寫:

services.AddSignalR()
    .AddJsonProtocol(options => {
        options.PayloadSerializerOptions.PropertyNamingPolicy = null;
    });

  b)服務端常用配置屬性:

   屬性配置使用方式:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR(hubOptions =>
    {
        hubOptions.EnableDetailedErrors = true;
        hubOptions.KeepAliveInterval = TimeSpan.FromMinutes(1);
    });
}

   配置屬性說明如下:

選項預設值說明
ClientTimeoutInterval 30 秒 如果客戶端未收到訊息 (在此時間間隔內包含 keep-alive) ,伺服器將認為客戶端已斷開連線。 由於實現方式的原因,客戶端實際標記為斷開連線可能需要更長的時間。 建議值為值的兩倍 KeepAliveInterval 。
HandshakeTimeout 15 秒 如果客戶端在此時間間隔內未傳送初始握手訊息,連線將關閉。 這是一種高階設定,只應在握手超時錯誤由於嚴重網路延遲而發生時進行修改。 有關握手過程的詳細資訊
KeepAliveInterval 15 秒 如果伺服器未在此時間間隔內傳送訊息,則會自動傳送 ping 訊息,使連線保持開啟狀態。 更改時 KeepAliveInterval ,請更改 ServerTimeout / serverTimeoutInMilliseconds 客戶端上的設定。 建議 ServerTimeout / serverTimeoutInMilliseconds 值為值的兩倍 KeepAliveInterval 。
SupportedProtocols 所有已安裝的協議 此中心支援的協議。 預設情況下,將允許在伺服器上註冊的所有協議,但可以從此列表中刪除協議,以禁用各個集線器的特定協議。
EnableDetailedErrors false 如果為,則在 true 集線器方法中引發異常時,詳細的異常訊息將返回到客戶端。 預設值為 false ,因為這些異常訊息可能包含敏感資訊。
StreamBufferCapacity 10 可為客戶端上載流緩衝的最大項數。 如果達到此限制,則會阻止處理呼叫,直到伺服器處理流項。
MaximumReceiveMessageSize 32 KB 單個傳入集線器訊息的最大大小。
MaximumParallelInvocationsPerClient 1 每個客戶端可以在進行排隊之前並行呼叫的最大集線器方法數。


 2、如何提升Signalr傳輸效能:

  使用MessagePackc傳輸:MessagePack 是一種快速、精簡的二進位制序列化格式。 當效能和頻寬需要考慮時,它很有用,因為它會建立比 JSON更小的訊息。

  在檢視網路跟蹤和日誌時,不能讀取二進位制訊息,除非這些位元組是通過 MessagePack 分析器傳遞的。 SignalR 提供對 MessagePack 格式的內建支援,併為客戶端和伺服器提供要使用的 Api。

  使用方式:新增包Microsoft.AspNetCore.SignalR.Protocols.MessagePack,在 Startup.ConfigureServices 方法中,將新增 AddMessagePackProtocol 到在 AddSignalR 伺服器上啟用 MessagePack 支援的呼叫

services.AddSignalR().AddMessagePackProtocol();

參考:

 https://docs.microsoft.com/zh-cn/aspnet/core/signalr/introduction

相關文章