网络层优化 (#152)

This commit is contained in:
yeziuku 2026-04-05 22:53:33 +08:00 committed by GitHub
parent ce29844593
commit a6087f98a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 79 additions and 42 deletions

View File

@ -27,10 +27,14 @@ namespace Milimoe.FunGame.Core.Api.Transmittal
/// </summary> /// </summary>
public bool IsDisposed => _isDisposed; public bool IsDisposed => _isDisposed;
// 获取ResultData中key值对应的Json字符串 /// <summary>
// -- 此索引器仅返回Json字符串对象类型请使用反序列化方法GetResult<T>() -- /// 获取ResultData中key值对应的Json字符串
// -- 当然也可以自己反序列化 -- /// <para/>-- 此索引器仅返回Json字符串对象类型请使用反序列化方法GetResult{T}() --
// -- 基本类型可能有效,但仍建议使用反序列化方法 -- /// <para/>-- 当然也可以自己反序列化 --
/// <para/>-- 基本类型可能有效,但仍建议使用反序列化方法 --
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object? this[string key] public object? this[string key]
{ {
get get

View File

@ -21,14 +21,14 @@ namespace Milimoe.FunGame.Core.Api.Utility
/// </summary> /// </summary>
public TaskScheduler() public TaskScheduler()
{ {
Task.Factory.StartNew(async () => Task.Run(async () =>
{ {
while (true) while (true)
{ {
CheckAndRunTasks(); CheckAndRunTasks();
await Task.Delay(1000); await Task.Delay(1000);
} }
}, TaskCreationOptions.LongRunning); });
} }
/// <summary> /// <summary>

View File

@ -520,7 +520,7 @@ namespace Milimoe.FunGame.Core.Controller
/// </summary> /// </summary>
protected void StartReceiving() protected void StartReceiving()
{ {
_ReceivingTask = Task.Factory.StartNew(() => _ReceivingTask = Task.Run(() =>
{ {
Thread.Sleep(100); Thread.Sleep(100);
_IsReceiving = true; _IsReceiving = true;

View File

@ -1,20 +1,25 @@
using Milimoe.FunGame.Core.Interface.Sockets; using System.Diagnostics;
using Milimoe.FunGame.Core.Interface.Sockets;
using Milimoe.FunGame.Core.Library.Common.Network; using Milimoe.FunGame.Core.Library.Common.Network;
using Milimoe.FunGame.Core.Library.Constant; using Milimoe.FunGame.Core.Library.Constant;
namespace Milimoe.FunGame.Core.Library.Common.Architecture namespace Milimoe.FunGame.Core.Library.Common.Architecture
{ {
public class HeartBeat : ISocketHeartBeat internal class HeartBeat : ISocketHeartBeat
{ {
public TransmittalType TransmittalType { get; } = TransmittalType.Socket; public TransmittalType TransmittalType { get; } = TransmittalType.Socket;
public bool SendingHeartBeat => _sendingHeartBeat; public bool SendingHeartBeat => _sendingHeartBeat;
public int HeartBeatFaileds => _heartBeatFaileds; public int HeartBeatFaileds => _heartBeatFaileds;
public int Ping => Math.Min(_ping, 999);
private Task? _sendingHeartBeatTask; private Task? _sendingHeartBeatTask;
private bool _sendingHeartBeat = false; private bool _sendingHeartBeat = false;
private bool _lastHeartbeatReceived = false;
private int _heartBeatFaileds = 0; 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 Socket? _socket = null;
private readonly HTTPClient? _httpClient = null; private readonly HTTPClient? _httpClient = null;
@ -37,7 +42,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
_sendingHeartBeat = true; _sendingHeartBeat = true;
_socket?.AddSocketObjectHandler(SocketObject_Handler); _socket?.AddSocketObjectHandler(SocketObject_Handler);
_httpClient?.AddSocketObjectHandler(SocketObject_Handler); _httpClient?.AddSocketObjectHandler(SocketObject_Handler);
_sendingHeartBeatTask = Task.Factory.StartNew(SendHeartBeat); _sendingHeartBeatTask = Task.Run(SendHeartBeat);
} }
} }
@ -55,39 +60,45 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
try try
{ {
await Task.Delay(100); await Task.Delay(100);
if (_socket != null) while (_sendingHeartBeat)
{ {
while (_socket.Connected) // 发送心跳包
string probeId = Guid.NewGuid().ToString();
lock (_probeLock)
{ {
if (!SendingHeartBeat) _sendingHeartBeat = true; _currentProbeId = probeId;
// 发送心跳包 _lastSentTimestamp = Stopwatch.GetTimestamp();
_lastHeartbeatReceived = false; }
if (_socket.Send(SocketMessageType.HeartBeat) == SocketResult.Success) 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); await Task.Delay(4 * 1000);
if (!_lastHeartbeatReceived) AddHeartBeatFaileds(); lock (_probeLock)
{
if (_currentProbeId == probeId) throw new TimeOutException();
}
} }
else AddHeartBeatFaileds();
await Task.Delay(20 * 1000);
} }
} catch
else if (_httpClient != null)
{
while (_httpClient.WebSocket?.State == System.Net.WebSockets.WebSocketState.Open)
{ {
if (!SendingHeartBeat) _sendingHeartBeat = true; AddHeartBeatFaileds();
// 发送心跳包
_lastHeartbeatReceived = false;
if (await _httpClient.Send(SocketMessageType.HeartBeat) == SocketResult.Success)
{
await Task.Delay(4 * 1000);
if (!_lastHeartbeatReceived) AddHeartBeatFaileds();
}
else AddHeartBeatFaileds();
await Task.Delay(20 * 1000);
} }
await Task.Delay(20 * 1000);
} }
_sendingHeartBeat = false;
} }
catch (System.Exception e) catch (System.Exception e)
{ {
@ -102,12 +113,18 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
_httpClient.Close(); _httpClient.Close();
} }
} }
finally
{
_sendingHeartBeat = false;
}
} }
private void AddHeartBeatFaileds() private void AddHeartBeatFaileds()
{ {
_currentProbeId = "";
_ping = 999;
// 超过三次没回应心跳,服务器连接失败。 // 超过三次没回应心跳,服务器连接失败。
if (_heartBeatFaileds++ >= 3) if (++_heartBeatFaileds >= 3)
{ {
_socket?.Close(); _socket?.Close();
_httpClient?.Close(); _httpClient?.Close();
@ -119,8 +136,22 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
{ {
if (obj.SocketType == SocketMessageType.HeartBeat) if (obj.SocketType == SocketMessageType.HeartBeat)
{ {
_lastHeartbeatReceived = true; string receivedId = "";
_heartBeatFaileds = 0; 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 = "";
}
}
} }
} }
} }

View File

@ -20,6 +20,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
public string ServerNotice { get; } = ""; public string ServerNotice { get; } = "";
public bool Connected => WebSocket != null && WebSocket.State == WebSocketState.Open; public bool Connected => WebSocket != null && WebSocket.State == WebSocketState.Open;
public bool Receiving => _receiving; public bool Receiving => _receiving;
public int Ping => HeartBeat.Ping;
private HeartBeat HeartBeat { get; } private HeartBeat HeartBeat { get; }
public event Action<System.Exception>? ConnectionLost; public event Action<System.Exception>? ConnectionLost;
@ -36,7 +37,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
ServerPort = serverPort; ServerPort = serverPort;
HeartBeat = new(this); HeartBeat = new(this);
HeartBeat.StartSendingHeartBeat(); HeartBeat.StartSendingHeartBeat();
Task.Factory.StartNew(async () => await StartListening(args)); Task.Run(async () => await StartListening(args));
} }
public static async Task<HTTPClient> Connect(string serverAddress, bool ssl, int serverPort = 0, string subUrl = "", params object[] args) public static async Task<HTTPClient> Connect(string serverAddress, bool ssl, int serverPort = 0, string subUrl = "", params object[] args)

View File

@ -17,6 +17,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
public string ServerNotice { get; } = ""; public string ServerNotice { get; } = "";
public bool Connected => Instance != null && Instance.Connected; public bool Connected => Instance != null && Instance.Connected;
public bool Receiving => _receiving; public bool Receiving => _receiving;
public int Ping => HeartBeat.Ping;
private HeartBeat HeartBeat { get; } private HeartBeat HeartBeat { get; }
public event Action<System.Exception>? ConnectionLost; public event Action<System.Exception>? ConnectionLost;
@ -28,9 +29,9 @@ namespace Milimoe.FunGame.Core.Library.Common.Network
private Socket(System.Net.Sockets.Socket instance, string serverAddress, int serverPort) private Socket(System.Net.Sockets.Socket instance, string serverAddress, int serverPort)
{ {
this.Instance = instance; Instance = instance;
this.ServerAddress = serverAddress; ServerAddress = serverAddress;
this.ServerPort = serverPort; ServerPort = serverPort;
HeartBeat = new(this); HeartBeat = new(this);
HeartBeat.StartSendingHeartBeat(); HeartBeat.StartSendingHeartBeat();
} }