起因:
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();