csharp-sdk-upm/Realtime/Internal/Connection/LCHeartBeat.cs

82 lines
2.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Threading;
using System.Threading.Tasks;
using LeanCloud.Common;
using LeanCloud.Realtime.Protocol;
namespace LeanCloud.Realtime.Internal.Connection {
/// <summary>
/// 心跳控制器,由于 .Net Standard 2.0 不支持发送 ping frame所以需要发送逻辑心跳
/// 1. 每次接收到消息后开始监听,如果在 pingInterval 时间内没有再次接收到消息,则发送 ping 请求;
/// 2. 发送后等待 pongInterval 时间,如果在此时间内接收到了任何消息,则取消并重新开始监听 1
/// 3. 如果没收到消息,则认为超时并回调,连接层接收回调后放弃当前连接,以断线逻辑处理
/// </summary>
internal class LCHeartBeat {
private readonly LCConnection connection;
/// <summary>
/// ping 间隔
/// </summary>
private readonly int pingInterval;
/// <summary>
/// pong 间隔
/// </summary>
private readonly int pongInterval;
private CancellationTokenSource pingCTS;
private CancellationTokenSource pongCTS;
internal LCHeartBeat(LCConnection connection,
int pingInterval,
int pongInterval) {
this.connection = connection;
this.pingInterval = pingInterval;
this.pongInterval = pongInterval;
}
/// <summary>
/// 更新心跳监听
/// </summary>
/// <returns></returns>
internal async Task Update(Action onTimeout) {
LCLogger.Debug("HeartBeat update");
pingCTS?.Cancel();
pongCTS?.Cancel();
// 计时准备 ping
pingCTS = new CancellationTokenSource();
Task delayTask = Task.Delay(pingInterval, pingCTS.Token);
await delayTask;
if (delayTask.IsCanceled) {
return;
}
// 发送 ping 包
LCLogger.Debug("Ping ~~~");
GenericCommand command = new GenericCommand {
Cmd = CommandType.Echo,
AppId = LCApplication.AppId,
PeerId = connection.id
};
_ = connection.SendRequest(command);
pongCTS = new CancellationTokenSource();
Task timeoutTask = Task.Delay(pongInterval, pongCTS.Token);
await timeoutTask;
if (timeoutTask.IsCanceled) {
return;
}
// timeout
LCLogger.Error("Ping timeout");
onTimeout.Invoke();
}
/// <summary>
/// 停止心跳监听
/// </summary>
internal void Stop() {
pingCTS?.Cancel();
pongCTS?.Cancel();
}
}
}