BITKit/Src/Core/Kcp/KcpNetClient.cs

332 lines
10 KiB
C#
Raw Normal View History

2023-06-29 14:57:11 +08:00
using System;
2024-06-08 10:07:40 +08:00
using System.Collections.Concurrent;
2023-10-06 23:43:19 +08:00
using System.Collections.Generic;
2024-06-24 17:30:44 +08:00
using System.Diagnostics.Tracing;
2023-08-23 01:59:26 +08:00
using System.Timers;
2023-06-29 14:57:11 +08:00
using Cysharp.Threading.Tasks;
using kcp2k;
2023-08-23 01:59:26 +08:00
using Timer = System.Timers.Timer;
using System.Threading.Tasks;
using System.IO;
2024-06-24 17:30:44 +08:00
using System.Linq;
2024-07-29 17:53:08 +08:00
using System.Net;
2023-08-23 01:59:26 +08:00
using System.Numerics;
2024-06-12 16:01:56 +08:00
using System.Reflection;
2024-06-22 17:58:05 +08:00
using System.Text;
2025-01-24 10:36:58 +08:00
using System.Threading;
2023-08-23 01:59:26 +08:00
using BITKit.Net.Examples;
2024-11-03 16:38:17 +08:00
using Microsoft.Extensions.Logging;
2023-08-23 01:59:26 +08:00
using Newtonsoft.Json;
2024-06-17 14:38:09 +08:00
using Unity.Mathematics;
2023-06-29 14:57:11 +08:00
namespace BITKit.Net
{
public class KcpNetClient:INetClient,INetProvider
{
2025-01-24 10:36:58 +08:00
private readonly NetProviderCommon _common = new();
2024-11-03 16:38:17 +08:00
private readonly ILogger<KcpNetClient> _logger;
public KcpNetClient(ILogger<KcpNetClient> logger)
{
_logger = logger;
_client = new KcpClient(
OnConnectedInternal,
OnData,
OnDisconnectInternal,
OnError,
KCPNet.Config
);
_timer.Elapsed += Tick;
_logger.LogInformation("已创建KCP客户端");
_isConnected.AddListener(ConnectionCallback);
}
2023-06-29 14:57:11 +08:00
public event Action OnStartConnect;
public event Action OnConnected;
public event Action OnDisconnected;
public event Action OnConnectedFailed;
2025-01-24 10:36:58 +08:00
public uint TickRate { get; set; } = 8;
2024-06-17 16:29:39 +08:00
public bool IsConnected => _isConnected;
2024-06-20 17:28:56 +08:00
public bool IsConnecting { get; private set; }
2024-07-29 09:39:22 +08:00
public bool AutoReconnect { get; set; } = true;
2024-11-03 16:38:17 +08:00
public float2 Traffic { get; private set; }
2024-03-31 23:31:00 +08:00
public bool ManualTick { get; set; }
2024-07-29 09:39:22 +08:00
private readonly IntervalUpdate _reconnectInterval = new(1);
2024-07-29 14:37:00 +08:00
2024-03-31 23:31:00 +08:00
public int Ping { get; private set; }
2023-08-23 01:59:26 +08:00
public int Id { get; private set; } = -1;
2024-11-03 16:38:17 +08:00
private readonly KcpClient _client;
2023-10-06 23:43:19 +08:00
2024-06-20 10:04:18 +08:00
private readonly ConcurrentQueue<byte[]> _commandQueue = new();
2023-10-06 23:43:19 +08:00
2024-03-31 23:31:00 +08:00
private DateTime _lastPingTime = DateTime.Now;
2023-08-23 01:59:26 +08:00
private readonly Timer _timer = new(100)
{
AutoReset = true
};
2024-03-31 23:31:00 +08:00
2024-06-07 12:56:34 +08:00
private readonly ValidHandle _isConnected = new();
2024-11-03 16:38:17 +08:00
private bool _userConnected;
2024-06-08 15:12:48 +08:00
private int _index = int.MinValue;
2025-01-24 18:11:03 +08:00
2024-06-20 10:55:18 +08:00
private DateTime _now = DateTime.Now;
private TimeSpan _interval = TimeSpan.FromMilliseconds(100);
2024-07-29 09:39:22 +08:00
private string _connectedAddress = "127.0.0.1";
private ushort _connectedPort = 27014;
2024-06-20 10:55:18 +08:00
2024-06-07 12:56:34 +08:00
private async void ConnectionCallback(bool x)
{
await BITApp.SwitchToMainThread();
2024-06-16 09:34:17 +08:00
if (x)
{
OnConnected?.Invoke();
2024-11-03 16:38:17 +08:00
_logger.LogInformation("连接成功");
2024-06-16 09:34:17 +08:00
}
else
{
OnDisconnected?.Invoke();
2024-11-03 16:38:17 +08:00
_logger.LogInformation("连接已断开");
2024-06-16 09:34:17 +08:00
}
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
2023-10-24 23:38:22 +08:00
private void Tick(object sender, ElapsedEventArgs e)
2023-08-23 01:59:26 +08:00
{
2024-03-31 23:31:00 +08:00
if (!ManualTick)
Tick();
2023-08-23 01:59:26 +08:00
}
public async void Disconnect()
2024-11-03 16:38:17 +08:00
{
_userConnected = false;
DisconnectInternal();
}
private async void DisconnectInternal()
2023-06-29 14:57:11 +08:00
{
2024-07-29 09:39:22 +08:00
IsConnecting = false;
2024-11-03 16:38:17 +08:00
_client.Disconnect();
2024-06-17 16:29:39 +08:00
_isConnected.RemoveElement(this);
2024-06-20 10:04:18 +08:00
_timer.Stop();
2023-08-23 01:59:26 +08:00
try
{
await BITApp.SwitchToMainThread();
2023-08-23 01:59:26 +08:00
OnDisconnected?.Invoke();
}
catch (OperationCanceledException){}
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
2024-11-03 16:38:17 +08:00
private string _lastHostName;
2023-08-23 01:59:26 +08:00
public async UniTask<bool> Connect(string address = "127.0.0.1", ushort port = 27014)
2023-06-29 14:57:11 +08:00
{
2024-08-05 09:53:22 +08:00
if (IsConnecting)
{
2025-01-12 11:57:37 +08:00
_logger.LogWarning("正在连接中");
2024-08-05 09:53:22 +08:00
return false;
}
2024-11-03 16:38:17 +08:00
_userConnected = true;
2025-01-24 10:36:58 +08:00
2024-07-29 17:53:08 +08:00
//如果address是域名,解析为Ip
if (address.Contains("."))
{
var ip = await Dns.GetHostAddressesAsync(address);
if (ip.Length > 0)
{
address = ip[0].ToString();
2024-11-03 16:38:17 +08:00
if (_lastHostName != address)
{
_logger.LogInformation($"解析域名:{address},IP:{ip}");
_lastHostName = address;
}
2024-07-29 17:53:08 +08:00
}
}
2024-08-05 09:53:22 +08:00
if (address is not "127.0.0.1")
_connectedAddress = address;
if (port is not 27014)
_connectedPort = port;
2024-07-29 17:53:08 +08:00
2024-06-20 17:28:56 +08:00
IsConnecting = true;
2024-11-03 16:38:17 +08:00
if (_client.connected) return false;
await BITApp.SwitchToMainThread();
2023-08-11 23:57:37 +08:00
OnStartConnect?.Invoke();
2023-06-29 14:57:11 +08:00
await UniTask.SwitchToThreadPool();
try
{
2025-01-24 18:11:03 +08:00
_common.LastHeartbeat.GetOrCreate(0);
_common.LastHeartbeat[0] = DateTime.Now;
2024-11-03 16:38:17 +08:00
_client.Connect(address, port);
2023-08-23 01:59:26 +08:00
_timer.Start();
2024-06-20 10:55:18 +08:00
_interval = TimeSpan.FromMilliseconds(_timer.Interval);
2024-06-20 17:28:56 +08:00
2025-01-24 10:36:58 +08:00
if (_client.connected)
{
HandShake();
_client.Send(new[] { (byte)NetCommandType.Heartbeat }, KcpChannel.Reliable);
Traffic += new float2(1, 0);
}
2024-11-03 16:38:17 +08:00
_client.Tick();
2024-06-07 12:56:34 +08:00
await Task.Delay(100);
2024-06-20 17:28:56 +08:00
2024-11-03 16:38:17 +08:00
if (_client.connected)
2024-06-16 17:55:29 +08:00
{
2024-06-20 17:28:56 +08:00
SendServerMessage(Environment.MachineName);
IsConnecting = false;
2024-07-29 09:39:22 +08:00
_connectedAddress = address;
_connectedPort = port;
2025-01-24 18:11:03 +08:00
2025-01-24 10:36:58 +08:00
2024-11-03 16:38:17 +08:00
return _client.connected;
2024-06-16 17:55:29 +08:00
}
2024-06-20 17:28:56 +08:00
OnConnectedFailed?.Invoke();
2024-11-03 16:38:17 +08:00
DisconnectInternal();
2024-06-20 17:28:56 +08:00
IsConnecting = false;
return false;
2023-06-29 14:57:11 +08:00
}
catch (Exception e)
{
2025-01-12 11:57:37 +08:00
_logger.LogCritical(e,e.Message);
2023-08-23 01:59:26 +08:00
if (BITApp.SynchronizationContext is not null)
await UniTask.SwitchToSynchronizationContext(BITApp.SynchronizationContext);
2023-06-29 14:57:11 +08:00
OnConnectedFailed?.Invoke();
2024-06-20 10:04:18 +08:00
_timer.Stop();
2024-06-20 17:28:56 +08:00
IsConnecting = false;
2023-06-29 14:57:11 +08:00
return false;
}
}
2024-06-12 16:01:56 +08:00
private void OnData(ArraySegment<byte> bytes, KcpChannel channel)
{
try
{
2024-06-17 14:38:09 +08:00
Traffic+=new float2(0,bytes.Count);
2025-01-24 18:11:03 +08:00
OnDataInternal(bytes, channel);
2024-06-12 16:01:56 +08:00
}
catch (Exception e)
{
2025-01-12 11:57:37 +08:00
_logger.LogCritical(e,e.Message);
2024-06-12 16:01:56 +08:00
}
}
2025-01-24 18:11:03 +08:00
private void OnDataInternal(ArraySegment<byte> bytes, KcpChannel channel)
2023-06-29 14:57:11 +08:00
{
2025-01-24 18:11:03 +08:00
try
2023-08-23 01:59:26 +08:00
{
2025-01-24 18:11:03 +08:00
_common.OnDataInternal(0,bytes,channel);
}
catch (Exception e)
{
_logger.LogCritical(e,e.Message);
2023-08-23 01:59:26 +08:00
}
2025-01-24 18:11:03 +08:00
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
private async void OnConnectedInternal()
2023-06-29 14:57:11 +08:00
{
2025-01-24 18:11:03 +08:00
2023-06-29 14:57:11 +08:00
}
2023-08-23 01:59:26 +08:00
private async void OnDisconnectInternal()
2023-06-29 14:57:11 +08:00
{
2024-11-03 16:38:17 +08:00
DisconnectInternal();
2023-06-29 14:57:11 +08:00
}
private void OnError(ErrorCode errorCode, string message)
{
2024-11-03 16:38:17 +08:00
_logger.LogInformation($"{_client.remoteEndPoint}异常:{errorCode},{message}");
2023-06-29 14:57:11 +08:00
}
2024-08-06 10:27:59 +08:00
2023-06-29 14:57:11 +08:00
2023-08-23 01:59:26 +08:00
public void SendServerMessage(string message)
{
var bytes = BinaryBuilder
.Create()
.Write(((byte)NetCommandType.Message))
.Write(message)
.Build();
2024-06-17 14:38:09 +08:00
Traffic+=new float2(bytes.Length,0);
2024-11-03 16:38:17 +08:00
_client.Send(bytes, KcpChannel.Reliable);
2023-08-23 01:59:26 +08:00
}
2024-03-31 23:31:00 +08:00
public void Tick()
{
2024-11-03 16:38:17 +08:00
_now = DateTime.Now;
if(_userConnected is false)return;
2024-06-12 17:57:35 +08:00
try
2024-03-31 23:31:00 +08:00
{
2024-11-03 16:38:17 +08:00
if (_client.connected)
2024-06-17 16:29:39 +08:00
{
2025-01-24 18:11:03 +08:00
if (DateTime.Now - _common.LastHeartbeat.GetOrCreate(0) > TimeSpan.FromSeconds(5))
2024-06-17 16:29:39 +08:00
{
2025-01-12 11:57:37 +08:00
_logger.LogWarning("心跳超时,自动断开");
2024-11-03 16:38:17 +08:00
DisconnectInternal();
2024-06-20 17:28:56 +08:00
_commandQueue.Clear();
return;
2024-06-17 16:29:39 +08:00
}
2024-06-20 17:28:56 +08:00
while (_commandQueue.TryDequeue(out var bytes))
{
Traffic += new float2(bytes.Length, 0);
2024-11-03 16:38:17 +08:00
_client.Send(bytes, KcpChannel.Reliable);
2024-06-20 17:28:56 +08:00
}
2024-07-26 15:45:10 +08:00
Traffic+=new float2(1,0);
2025-01-24 10:36:58 +08:00
_client.Send(_common.HeartBeat, KcpChannel.Unreliable);
2024-06-17 16:29:39 +08:00
}
2024-06-20 17:28:56 +08:00
else
2024-06-12 17:57:35 +08:00
{
2024-07-29 09:39:22 +08:00
if (AutoReconnect && _reconnectInterval.AllowUpdate)
{
if (IsConnecting is false)
{
Connect(_connectedAddress,_connectedPort).Forget();
}
}
2024-06-20 17:28:56 +08:00
if (_commandQueue.Count > 0)
{
_commandQueue.Clear();
//BIT4Log.Warning<KcpNetClient>("连接已断开,清空指令队列");
}
2024-06-12 17:57:35 +08:00
}
2024-11-03 16:38:17 +08:00
_client.Tick();
2024-06-12 17:57:35 +08:00
}
catch (Exception e)
{
2025-01-12 11:57:37 +08:00
_logger.LogCritical(e,e.Message);
2024-06-12 17:57:35 +08:00
}
2024-03-31 23:31:00 +08:00
}
2023-08-23 01:59:26 +08:00
public void HandShake()
{
// send client to server
2024-06-17 14:38:09 +08:00
Traffic+=new float2(2,0);
2024-11-03 16:38:17 +08:00
_client.Send(new byte[]{0x01, 0x02}, KcpChannel.Reliable);
2023-08-23 01:59:26 +08:00
}
2025-01-24 18:11:03 +08:00
public T GetRemoteInterface<T>() => _common.GetRemoteInterface<T>();
public void Invoke(Memory<byte> bytes)
{
throw new NotImplementedException();
}
public UniTask<Memory<byte>> InvokeAsync(Memory<byte> bytes)
{
throw new NotImplementedException();
}
public void Invoke(IReadOnlyList<byte> bytes)
{
throw new NotImplementedException();
}
public UniTask<IReadOnlyList<byte>> InvokeAsync(IReadOnlyList<byte> bytes)
{
throw new NotImplementedException();
}
2023-06-29 14:57:11 +08:00
}
}