mirror of
https://github.com/project-redbud/FunGame-Core.git
synced 2026-04-20 05:24:59 +00:00
159 lines
5.5 KiB
C#
159 lines
5.5 KiB
C#
using System.Diagnostics;
|
|
using Milimoe.FunGame.Core.Interface.Sockets;
|
|
using Milimoe.FunGame.Core.Library.Common.Network;
|
|
using Milimoe.FunGame.Core.Library.Constant;
|
|
|
|
namespace Milimoe.FunGame.Core.Library.Common.Architecture
|
|
{
|
|
internal class HeartBeat : ISocketHeartBeat
|
|
{
|
|
public TransmittalType TransmittalType { get; } = TransmittalType.Socket;
|
|
public bool SendingHeartBeat => _sendingHeartBeat;
|
|
public int HeartBeatFaileds => _heartBeatFaileds;
|
|
public int Ping => Math.Min(_ping, 999);
|
|
|
|
private Task? _sendingHeartBeatTask;
|
|
private bool _sendingHeartBeat = false;
|
|
private int _heartBeatFaileds = 0;
|
|
private string _currentProbeId = "";
|
|
private long _lastSentTimestamp;
|
|
private int _ping = 0;
|
|
|
|
private readonly Lock _probeLock = new();
|
|
private readonly Socket? _socket = null;
|
|
private readonly HTTPClient? _httpClient = null;
|
|
|
|
public HeartBeat(Socket socket)
|
|
{
|
|
_socket = socket;
|
|
TransmittalType = TransmittalType.Socket;
|
|
}
|
|
|
|
public HeartBeat(HTTPClient client)
|
|
{
|
|
_httpClient = client;
|
|
TransmittalType = TransmittalType.WebSocket;
|
|
}
|
|
|
|
public void StartSendingHeartBeat()
|
|
{
|
|
if (!FunGameInfo.FunGame_DebugMode)
|
|
{
|
|
_sendingHeartBeat = true;
|
|
_socket?.AddSocketObjectHandler(SocketObject_Handler);
|
|
_httpClient?.AddSocketObjectHandler(SocketObject_Handler);
|
|
_sendingHeartBeatTask = Task.Run(SendHeartBeat);
|
|
}
|
|
}
|
|
|
|
public void StopSendingHeartBeat()
|
|
{
|
|
_sendingHeartBeat = false;
|
|
_sendingHeartBeatTask?.Wait(1);
|
|
_sendingHeartBeatTask = null;
|
|
_socket?.RemoveSocketObjectHandler(SocketObject_Handler);
|
|
_httpClient?.RemoveSocketObjectHandler(SocketObject_Handler);
|
|
}
|
|
|
|
private async Task SendHeartBeat()
|
|
{
|
|
try
|
|
{
|
|
await Task.Delay(100);
|
|
while (_sendingHeartBeat)
|
|
{
|
|
// 发送心跳包
|
|
string probeId = Guid.NewGuid().ToString();
|
|
lock (_probeLock)
|
|
{
|
|
_currentProbeId = probeId;
|
|
_lastSentTimestamp = Stopwatch.GetTimestamp();
|
|
}
|
|
try
|
|
{
|
|
bool sendSuccess = false;
|
|
if (_socket != null)
|
|
{
|
|
sendSuccess = _socket.Connected && _socket.Send(SocketMessageType.HeartBeat, _currentProbeId) == SocketResult.Success;
|
|
}
|
|
else if (_httpClient != null)
|
|
{
|
|
sendSuccess = _httpClient.WebSocket?.State == System.Net.WebSockets.WebSocketState.Open && await _httpClient.Send(SocketMessageType.HeartBeat, _currentProbeId) == SocketResult.Success;
|
|
}
|
|
if (!sendSuccess)
|
|
{
|
|
throw new ConnectFailedException();
|
|
}
|
|
else
|
|
{
|
|
await Task.Delay(4 * 1000);
|
|
lock (_probeLock)
|
|
{
|
|
if (_currentProbeId == probeId) throw new TimeOutException();
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
AddHeartBeatFaileds();
|
|
}
|
|
await Task.Delay(20 * 1000);
|
|
}
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
if (_socket != null)
|
|
{
|
|
_socket.OnConnectionLost(e);
|
|
_socket.Close();
|
|
}
|
|
if (_httpClient != null)
|
|
{
|
|
_httpClient.OnConnectionLost(e);
|
|
_httpClient.Close();
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
_sendingHeartBeat = false;
|
|
}
|
|
}
|
|
|
|
private void AddHeartBeatFaileds()
|
|
{
|
|
_currentProbeId = "";
|
|
_ping = 999;
|
|
// 超过三次没回应心跳,服务器连接失败。
|
|
if (++_heartBeatFaileds >= 3)
|
|
{
|
|
_socket?.Close();
|
|
_httpClient?.Close();
|
|
throw new LostConnectException();
|
|
}
|
|
}
|
|
|
|
private void SocketObject_Handler(SocketObject obj)
|
|
{
|
|
if (obj.SocketType == SocketMessageType.HeartBeat)
|
|
{
|
|
string receivedId = "";
|
|
if (obj.Length > 0)
|
|
{
|
|
receivedId = obj.GetParam<string>(0) ?? "";
|
|
}
|
|
lock (_probeLock)
|
|
{
|
|
if (receivedId == _currentProbeId && !string.IsNullOrEmpty(_currentProbeId))
|
|
{
|
|
long elapsedTicks = Stopwatch.GetTimestamp() - _lastSentTimestamp;
|
|
double rttMs = elapsedTicks * 1000.0 / Stopwatch.Frequency;
|
|
_ping = (int)Math.Round(rttMs);
|
|
_heartBeatFaileds = 0;
|
|
_currentProbeId = "";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|