2024-11-03 16:42:23 +08:00
|
|
|
using System;
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Timers;
|
|
|
|
using Cysharp.Threading.Tasks;
|
|
|
|
using kcp2k;
|
|
|
|
using Newtonsoft.Json;
|
|
|
|
using Timer = System.Timers.Timer;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Net;
|
|
|
|
using System.Net.Sockets;
|
|
|
|
using System.Reflection;
|
2025-02-24 23:03:39 +08:00
|
|
|
using System.Threading;
|
2024-11-03 16:42:23 +08:00
|
|
|
using System.Threading.Tasks;
|
|
|
|
using System.Windows.Markup;
|
|
|
|
using BITKit.Net.Examples;
|
2025-02-24 23:03:39 +08:00
|
|
|
using Microsoft.Extensions.Logging;
|
2024-11-03 16:42:23 +08:00
|
|
|
|
|
|
|
namespace BITKit.Net
|
|
|
|
{
|
|
|
|
public class KCPNetServer:INetServer,INetProvider
|
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
private readonly NetProviderCommon _common = new();
|
|
|
|
private readonly ILogger<KCPNetServer> _logger;
|
2024-11-03 16:42:23 +08:00
|
|
|
public string Name { get; set; } = "Default";
|
2025-02-24 23:03:39 +08:00
|
|
|
public uint TickRate { get; set; } = 8;
|
2024-11-03 16:42:23 +08:00
|
|
|
public bool ManualTick { get; set; }
|
|
|
|
public event Action<int> OnClientConnected;
|
|
|
|
public event Action<int> OnClientDisconnected;
|
|
|
|
public event Action OnStartServer;
|
|
|
|
public event Action OnStopServer;
|
|
|
|
private readonly KcpServer server;
|
2025-02-24 23:03:39 +08:00
|
|
|
|
2024-11-03 16:42:23 +08:00
|
|
|
private bool _isStarted;
|
|
|
|
private readonly Timer _timer = new(100)
|
|
|
|
{
|
|
|
|
AutoReset = true
|
|
|
|
};
|
|
|
|
|
|
|
|
private int _index = 1001;
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
private DateTime _now=DateTime.UtcNow;
|
2024-11-03 16:42:23 +08:00
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
public KCPNetServer(ILogger<KCPNetServer> logger)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
_logger = logger;
|
2024-11-03 16:42:23 +08:00
|
|
|
server = new KcpServer(
|
|
|
|
OnConnected,
|
|
|
|
OnData,
|
|
|
|
OnDisconnect,
|
|
|
|
OnError,
|
|
|
|
KCPNet.Config
|
|
|
|
);
|
|
|
|
_timer.Elapsed += Tick;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void Tick(object sender, ElapsedEventArgs e)
|
|
|
|
{
|
|
|
|
_now = DateTime.UtcNow;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (_isStarted && IsRunningServer is false)
|
|
|
|
{
|
|
|
|
StartServer(_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (var id in Connections.Keys.ToArray())
|
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
server.Send(id,_common.HeartBeat , KcpChannel.Unreliable);
|
|
|
|
if (!_common.LastHeartbeat.TryGetValue(id, out var time)) continue;
|
2024-11-03 16:42:23 +08:00
|
|
|
if (!((_now - time).TotalSeconds > 3)) continue;
|
|
|
|
server.Disconnect(id);
|
2025-02-24 23:03:39 +08:00
|
|
|
_common.LastHeartbeat.TryRemove(id);
|
|
|
|
_logger.LogInformation($"{Name}:链接{id}超时,已断开");
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (server.IsActive() is false) return;
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
_common.DropCount.Clear();
|
|
|
|
while (_common.SendQueue.TryDequeue(out var value))
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
if (server.connections.ContainsKey(value.id))
|
|
|
|
{
|
|
|
|
server.Send(value.id, value.bytes, KcpChannel.Reliable);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int UpdateValueFactory(int i, int i1) => i1 + value.bytes.Length;
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
_common.DropCount.AddOrUpdate(value.id,value.bytes.Length,UpdateValueFactory);
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
}
|
2025-02-24 23:03:39 +08:00
|
|
|
foreach (var (id,length) in _common.DropCount)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
_logger.LogInformation($"未找到链接:{id},已丢弃字节数量:{length}");
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
2025-02-24 23:03:39 +08:00
|
|
|
|
|
|
|
server.Tick();
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
catch (SocketException)
|
|
|
|
{
|
|
|
|
//丢失链接,有用户断开连接,通常是正常现象
|
|
|
|
}
|
|
|
|
catch (Exception exception)
|
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
_logger.LogCritical(exception,exception.Message);
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private ushort _port;
|
|
|
|
public void StartServer(ushort port = 27014)
|
|
|
|
{
|
|
|
|
_port = port;
|
|
|
|
if (IsRunningServer is false)
|
|
|
|
{
|
|
|
|
if (TickRate > 0)
|
|
|
|
{
|
|
|
|
_timer.Interval = 1000f / TickRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
OnStartServer?.Invoke();
|
|
|
|
server.Start(port);
|
|
|
|
if (ManualTick is false)
|
|
|
|
_timer.Start();
|
|
|
|
_isStarted = true;
|
2025-02-24 23:03:39 +08:00
|
|
|
_logger.LogInformation($"已启动KCP服务器:{port}");
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BIT4Log.Warning<KCPNetServer>($"KCP服务器已经启动,忽略此次请求");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
public void StopServer(bool dispose = false)
|
|
|
|
{
|
|
|
|
if (IsRunningServer)
|
|
|
|
{
|
|
|
|
_isStarted = false;
|
|
|
|
server.Stop();
|
|
|
|
OnStopServer?.Invoke();
|
|
|
|
_timer.Stop();
|
2025-02-24 23:03:39 +08:00
|
|
|
_logger.LogInformation($"已停止KCP服务器");
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BIT4Log.Warning<KCPNetServer>($"KCP服务器未运行,忽略此次请求");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public bool IsRunningServer => server.IsActive();
|
|
|
|
public void SendMessageToClient(int id, string message)
|
|
|
|
{
|
|
|
|
using var ms = new MemoryStream();
|
|
|
|
using var writer = new BinaryWriter(ms);
|
|
|
|
writer.Write((byte)NetCommandType.Message);
|
|
|
|
writer.Write(message);
|
2025-02-24 23:03:39 +08:00
|
|
|
_common.SendQueue.Enqueue((id,ms.ToArray()));
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void SendMessageToAll(string message)
|
|
|
|
{
|
|
|
|
foreach (var Id in server.connections.Keys)
|
|
|
|
{
|
|
|
|
SendMessageToClient(Id,message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public IDictionary<int, EndPoint> Connections =>
|
|
|
|
new Dictionary<int, EndPoint>(
|
|
|
|
server.connections.Select(x => new KeyValuePair<int, EndPoint>(x.Key, x.Value.remoteEndPoint)
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
|
|
public void Tick()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Tick(null,null);
|
|
|
|
}
|
|
|
|
catch (SocketException)
|
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
_logger.LogInformation("有用户断开连接,如有异常请检查");
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void HandShake()
|
|
|
|
{
|
|
|
|
foreach (var id in server.connections.Keys)
|
|
|
|
{
|
|
|
|
server.Send(id, new byte[]{0x03, 0x04}, KcpChannel.Reliable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
public T GetRemoteInterface<T>() => _common.GetRemoteInterface<T>();
|
|
|
|
public void Invoke(Memory<byte> bytes)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
throw new NotImplementedException();
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
public UniTask<Memory<byte>> InvokeAsync(Memory<byte> bytes)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
throw new NotImplementedException();
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
public void Invoke(IReadOnlyList<byte> bytes)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
throw new NotImplementedException();
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
public UniTask<IReadOnlyList<byte>> InvokeAsync(IReadOnlyList<byte> bytes)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
throw new NotImplementedException();
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
private void OnConnectedInternel(int id)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
OnClientConnected?.Invoke(id);
|
|
|
|
_logger.LogInformation($"{id}已连接到:{Name}");
|
|
|
|
SendMessageToClient(id, $"成功连接到服务器:{Name}");
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
2025-02-24 23:03:39 +08:00
|
|
|
private void OnConnected(int Id)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
|
|
|
}
|
2025-02-24 23:03:39 +08:00
|
|
|
private void OnDisconnect(int Id)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
OnClientDisconnected?.Invoke(Id);
|
|
|
|
_logger.LogInformation($"{Id}已断开");
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
private void OnData(int Id, ArraySegment<byte> bytes, KcpChannel channel)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
try
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
_common.OnDataInternal(Id, bytes, channel);
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
2025-02-24 23:03:39 +08:00
|
|
|
catch (Exception e)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
_logger.LogCritical(e, e.Message);
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-24 23:03:39 +08:00
|
|
|
private void OnError(int Id, ErrorCode errorCode, string message)
|
2024-11-03 16:42:23 +08:00
|
|
|
{
|
2025-02-24 23:03:39 +08:00
|
|
|
_logger.LogInformation($"异常:{errorCode},{message}");
|
2024-11-03 16:42:23 +08:00
|
|
|
}
|
2025-02-24 23:03:39 +08:00
|
|
|
|
2024-11-03 16:42:23 +08:00
|
|
|
public void KickClient(int id)
|
|
|
|
{
|
|
|
|
server.Disconnect(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|