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