From 32c2491d25ee42922295d68099b73a4473a5d7fc Mon Sep 17 00:00:00 2001 From: EonaCat Date: Thu, 21 Aug 2025 18:55:11 +0200 Subject: [PATCH] Added nicknames --- EonaCat.Connections.Client/Program.cs | 4 + EonaCat.Connections.Server/Program.cs | 20 ++- .../EonaCat.Connections.csproj | 2 +- .../EventArguments/ConnectionEventArgs.cs | 2 + .../EventArguments/DataReceivedEventArgs.cs | 1 + .../NicknameConnectionEventArgs.cs | 7 -- EonaCat.Connections/NetworkClient.cs | 119 ++++++++++-------- EonaCat.Connections/NetworkServer.cs | 35 +++--- README.md | 50 +++++--- 9 files changed, 145 insertions(+), 95 deletions(-) delete mode 100644 EonaCat.Connections/EventArguments/NicknameConnectionEventArgs.cs diff --git a/EonaCat.Connections.Client/Program.cs b/EonaCat.Connections.Client/Program.cs index a725095..f6bfa15 100644 --- a/EonaCat.Connections.Client/Program.cs +++ b/EonaCat.Connections.Client/Program.cs @@ -46,13 +46,17 @@ namespace EonaCat.Connections.Client.Example // Subscribe to events _client.OnConnected += (sender, e) => + { Console.WriteLine($"Connected to server at {e.RemoteEndPoint}"); + }; _client.OnDataReceived += (sender, e) => Console.WriteLine($"Server says: {(e.IsBinary ? $"{e.Data.Length} bytes" : e.StringData)}"); _client.OnDisconnected += (sender, e) => + { Console.WriteLine("Disconnected from server"); + }; await _client.ConnectAsync(); diff --git a/EonaCat.Connections.Server/Program.cs b/EonaCat.Connections.Server/Program.cs index 817cc96..1247624 100644 --- a/EonaCat.Connections.Server/Program.cs +++ b/EonaCat.Connections.Server/Program.cs @@ -53,7 +53,14 @@ namespace EonaCat.Connections.Server.Example _server.OnDataReceived += async (sender, e) => { - Console.WriteLine($"Received from {e.ClientId}: {(e.IsBinary ? $"{e.Data.Length} bytes" : e.StringData)}"); + if (e.HasNickname) + { + Console.WriteLine($"Received from {e.Nickname}: {(e.IsBinary ? $"{e.Data.Length} bytes" : e.StringData)}"); + } + else + { + Console.WriteLine($"Received from {e.ClientId}: {(e.IsBinary ? $"{e.Data.Length} bytes" : e.StringData)}"); + } // Echo back the message if (e.IsBinary) @@ -67,7 +74,16 @@ namespace EonaCat.Connections.Server.Example }; _server.OnDisconnected += (sender, e) => - Console.WriteLine($"Client {e.ClientId} disconnected"); + { + if (e.HasNickname) + { + Console.WriteLine($"Client {e.Nickname} disconnected"); + } + else + { + Console.WriteLine($"Client {e.ClientId} disconnected"); + } + }; await _server.StartAsync(); } diff --git a/EonaCat.Connections/EonaCat.Connections.csproj b/EonaCat.Connections/EonaCat.Connections.csproj index e83ed5e..6b66553 100644 --- a/EonaCat.Connections/EonaCat.Connections.csproj +++ b/EonaCat.Connections/EonaCat.Connections.csproj @@ -11,7 +11,7 @@ EonaCat (Jeroen Saey) readme.md EonaCat.Connections - 1.0.3 + 1.0.4 EonaCat (Jeroen Saey) LICENSE EonaCat.png diff --git a/EonaCat.Connections/EventArguments/ConnectionEventArgs.cs b/EonaCat.Connections/EventArguments/ConnectionEventArgs.cs index ac03352..54b50ac 100644 --- a/EonaCat.Connections/EventArguments/ConnectionEventArgs.cs +++ b/EonaCat.Connections/EventArguments/ConnectionEventArgs.cs @@ -5,6 +5,8 @@ namespace EonaCat.Connections.EventArguments public class ConnectionEventArgs : EventArgs { public string ClientId { get; set; } + public string Nickname { get; set; } + public bool HasNickname => !string.IsNullOrEmpty(Nickname); public IPEndPoint RemoteEndPoint { get; set; } public DateTime Timestamp { get; set; } = DateTime.UtcNow; } diff --git a/EonaCat.Connections/EventArguments/DataReceivedEventArgs.cs b/EonaCat.Connections/EventArguments/DataReceivedEventArgs.cs index 46093d9..f6b2ef1 100644 --- a/EonaCat.Connections/EventArguments/DataReceivedEventArgs.cs +++ b/EonaCat.Connections/EventArguments/DataReceivedEventArgs.cs @@ -11,5 +11,6 @@ namespace EonaCat.Connections public DateTime Timestamp { get; internal set; } = DateTime.UtcNow; public IPEndPoint RemoteEndPoint { get; internal set; } public string Nickname { get; internal set; } + public bool HasNickname => !string.IsNullOrEmpty(Nickname); } } \ No newline at end of file diff --git a/EonaCat.Connections/EventArguments/NicknameConnectionEventArgs.cs b/EonaCat.Connections/EventArguments/NicknameConnectionEventArgs.cs deleted file mode 100644 index bfa062d..0000000 --- a/EonaCat.Connections/EventArguments/NicknameConnectionEventArgs.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace EonaCat.Connections.EventArguments -{ - public class NicknameConnectionEventArgs : ConnectionEventArgs - { - public string Nickname { get; set; } - } -} \ No newline at end of file diff --git a/EonaCat.Connections/NetworkClient.cs b/EonaCat.Connections/NetworkClient.cs index 6642a4a..afc0501 100644 --- a/EonaCat.Connections/NetworkClient.cs +++ b/EonaCat.Connections/NetworkClient.cs @@ -61,7 +61,7 @@ namespace EonaCat.Connections { try { - var sslStream = new SslStream(stream, false, userCertificateValidationCallback:_config.GetRemoteCertificateValidationCallback()); + var sslStream = new SslStream(stream, false, userCertificateValidationCallback: _config.GetRemoteCertificateValidationCallback()); if (_config.Certificate != null) { sslStream.AuthenticateAsClient(_config.Host, new X509CertificateCollection { _config.Certificate }, _config.CheckCertificateRevocation); @@ -111,21 +111,24 @@ namespace EonaCat.Connections public int Port => _config != null ? _config.Port : 0; private async Task ConnectUdp() { - try + await Task.Run(() => { - _udpClient = new UdpClient(); - _udpClient.Connect(_config.Host, _config.Port); - _isConnected = true; + try + { + _udpClient = new UdpClient(); + _udpClient.Connect(_config.Host, _config.Port); + _isConnected = true; - OnConnected?.Invoke(this, new ConnectionEventArgs { ClientId = "self", RemoteEndPoint = new IPEndPoint(IPAddress.Parse(_config.Host), _config.Port) }); + OnConnected?.Invoke(this, new ConnectionEventArgs { ClientId = "self", RemoteEndPoint = new IPEndPoint(IPAddress.Parse(_config.Host), _config.Port) }); - // Start receiving data - _ = Task.Run(() => ReceiveUdpDataAsync(), _cancellation.Token); - } - catch (Exception ex) - { - OnGeneralError?.Invoke(this, new ErrorEventArgs { Exception = ex, Message = "Failed to connect UDP" }); - } + // Start receiving data + _ = Task.Run(() => ReceiveUdpDataAsync(), _cancellation.Token); + } + catch (Exception ex) + { + OnGeneralError?.Invoke(this, new ErrorEventArgs { Exception = ex, Message = "Failed to connect UDP" }); + } + }); } @@ -232,46 +235,49 @@ namespace EonaCat.Connections private async Task ProcessReceivedDataAsync(byte[] data) { - try + await Task.Run(() => { - // Data is already decrypted if AES is enabled - // Just update stats / handle string conversion - - bool isBinary = true; - string stringData = null; - try { - stringData = Encoding.UTF8.GetString(data); - if (Encoding.UTF8.GetBytes(stringData).Length == data.Length) + // Data is already decrypted if AES is enabled + // Just update stats / handle string conversion + + bool isBinary = true; + string stringData = null; + + try { - isBinary = false; + stringData = Encoding.UTF8.GetString(data); + if (Encoding.UTF8.GetBytes(stringData).Length == data.Length) + { + isBinary = false; + } + } + catch + { + // Keep as binary + } + + OnDataReceived?.Invoke(this, new DataReceivedEventArgs + { + ClientId = "server", + Data = data, + StringData = stringData, + IsBinary = isBinary + }); + } + catch (Exception ex) + { + if (_config.UseAesEncryption) + { + OnEncryptionError?.Invoke(this, new ErrorEventArgs { Exception = ex, Message = "Error processing data" }); + } + else + { + OnGeneralError?.Invoke(this, new ErrorEventArgs { Exception = ex, Message = "Error processing data" }); } } - catch - { - // Keep as binary - } - - OnDataReceived?.Invoke(this, new DataReceivedEventArgs - { - ClientId = "server", - Data = data, - StringData = stringData, - IsBinary = isBinary - }); - } - catch (Exception ex) - { - if (_config.UseAesEncryption) - { - OnEncryptionError?.Invoke(this, new ErrorEventArgs { Exception = ex, Message = "Error processing data" }); - } - else - { - OnGeneralError?.Invoke(this, new ErrorEventArgs { Exception = ex, Message = "Error processing data" }); - } - } + }); } @@ -401,16 +407,19 @@ namespace EonaCat.Connections public async Task DisconnectAsync() { - _isConnected = false; - _cancellation?.Cancel(); - _tcpClient?.Close(); - _udpClient?.Close(); - _stream?.Dispose(); - _aesEncryption?.Dispose(); + await Task.Run(() => + { + _isConnected = false; + _cancellation?.Cancel(); + _tcpClient?.Close(); + _udpClient?.Close(); + _stream?.Dispose(); + _aesEncryption?.Dispose(); - OnDisconnected?.Invoke(this, new ConnectionEventArgs { ClientId = "self" }); + OnDisconnected?.Invoke(this, new ConnectionEventArgs { ClientId = "self" }); - _ = Task.Run(() => AutoReconnectAsync()); + _ = Task.Run(() => AutoReconnectAsync()); + }); } public void Dispose() diff --git a/EonaCat.Connections/NetworkServer.cs b/EonaCat.Connections/NetworkServer.cs index 04c853c..d9f151c 100644 --- a/EonaCat.Connections/NetworkServer.cs +++ b/EonaCat.Connections/NetworkServer.cs @@ -24,7 +24,7 @@ namespace EonaCat.Connections private readonly object _statsLock = new object(); public event EventHandler OnConnected; - public event EventHandler OnConnectedWithNickname; + public event EventHandler OnConnectedWithNickname; public event EventHandler OnDataReceived; public event EventHandler OnDisconnected; public event EventHandler OnSslError; @@ -346,7 +346,7 @@ namespace EonaCat.Connections { var nickname = stringData.Substring(9); client.Nickname = nickname; - OnConnectedWithNickname?.Invoke(this, new NicknameConnectionEventArgs + OnConnectedWithNickname?.Invoke(this, new ConnectionEventArgs { ClientId = client.Id, RemoteEndPoint = client.RemoteEndPoint, @@ -365,7 +365,7 @@ namespace EonaCat.Connections { client.Nickname = nickname; } - OnConnectedWithNickname?.Invoke(this, new NicknameConnectionEventArgs + OnConnectedWithNickname?.Invoke(this, new ConnectionEventArgs { ClientId = client.Id, RemoteEndPoint = client.RemoteEndPoint, @@ -486,7 +486,7 @@ namespace EonaCat.Connections Buffer.BlockCopy(lengthPrefix, 0, framed, 0, lengthPrefix.Length); Buffer.BlockCopy(data, 0, framed, lengthPrefix.Length, data.Length); - data = framed; // replace data with framed payload + data = framed; // replace the data with framed payload } if (_config.Protocol == ProtocolType.TCP) @@ -546,22 +546,25 @@ namespace EonaCat.Connections private async Task DisconnectClientAsync(string clientId) { - if (_clients.TryRemove(clientId, out var client)) + await Task.Run(() => { - try + if (_clients.TryRemove(clientId, out var client)) { - client.CancellationToken?.Cancel(); - client.TcpClient?.Close(); - client.Stream?.Dispose(); - client.AesEncryption?.Dispose(); + try + { + client.CancellationToken?.Cancel(); + client.TcpClient?.Close(); + client.Stream?.Dispose(); + client.AesEncryption?.Dispose(); - OnDisconnected?.Invoke(this, new ConnectionEventArgs { ClientId = clientId, RemoteEndPoint = client.RemoteEndPoint }); + OnDisconnected?.Invoke(this, new ConnectionEventArgs { ClientId = clientId, RemoteEndPoint = client.RemoteEndPoint, Nickname = client.Nickname }); + } + catch (Exception ex) + { + OnGeneralError?.Invoke(this, new ErrorEventArgs { ClientId = clientId, Exception = ex, Message = "Error disconnecting client" }); + } } - catch (Exception ex) - { - OnGeneralError?.Invoke(this, new ErrorEventArgs { ClientId = clientId, Exception = ex, Message = "Error disconnecting client" }); - } - } + }); } public void Stop() diff --git a/README.md b/README.md index 3023b22..16148ed 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,6 @@ servers and clients with optional TLS (for TCP) and optional application-layer e ## Server example: - using EonaCat.Connections; using EonaCat.Connections.Models; namespace EonaCat.Connections.Server.Example @@ -71,11 +70,12 @@ servers and clients with optional TLS (for TCP) and optional application-layer e var config = new Configuration { Protocol = ProtocolType.TCP, - Port = 8080, - UseSsl = true, + Port = 1111, + UseSsl = false, UseAesEncryption = true, MaxConnections = 100000, - ServerCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2("server.pfx", "p@ss"), + AesPassword = "EonaCat.Connections.Password", + //Certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2("server.pfx", "p@ss") }; _server = new NetworkServer(config); @@ -89,7 +89,14 @@ servers and clients with optional TLS (for TCP) and optional application-layer e _server.OnDataReceived += async (sender, e) => { - Console.WriteLine($"Received from {e.ClientId}: {(e.IsBinary ? $"{e.Data.Length} bytes" : e.StringData)}"); + if (e.HasNickname) + { + Console.WriteLine($"Received from {e.Nickname}: {(e.IsBinary ? $"{e.Data.Length} bytes" : e.StringData)}"); + } + else + { + Console.WriteLine($"Received from {e.ClientId}: {(e.IsBinary ? $"{e.Data.Length} bytes" : e.StringData)}"); + } // Echo back the message if (e.IsBinary) @@ -103,7 +110,16 @@ servers and clients with optional TLS (for TCP) and optional application-layer e }; _server.OnDisconnected += (sender, e) => - Console.WriteLine($"Client {e.ClientId} disconnected"); + { + if (e.HasNickname) + { + Console.WriteLine($"Client {e.Nickname} disconnected"); + } + else + { + Console.WriteLine($"Client {e.ClientId} disconnected"); + } + }; await _server.StartAsync(); } @@ -114,6 +130,7 @@ servers and clients with optional TLS (for TCP) and optional application-layer e using EonaCat.Connections; using EonaCat.Connections.Models; + using System.Text; namespace EonaCat.Connections.Client.Example { @@ -121,9 +138,9 @@ servers and clients with optional TLS (for TCP) and optional application-layer e { private static NetworkClient _client; - public static void Main(string[] args) + public static async Task Main(string[] args) { - CreateClientAsync().ConfigureAwait(false); + await CreateClientAsync().ConfigureAwait(false); while (true) { @@ -131,13 +148,13 @@ servers and clients with optional TLS (for TCP) and optional application-layer e var message = Console.ReadLine(); if (!string.IsNullOrEmpty(message) && message.Equals("exit", StringComparison.OrdinalIgnoreCase)) { - _client.DisconnectAsync().ConfigureAwait(false); + await _client.DisconnectAsync().ConfigureAwait(false); break; } if (!string.IsNullOrEmpty(message)) { - _client.SendAsync(message).ConfigureAwait(false); + await _client.SendAsync(message).ConfigureAwait(false); } } } @@ -148,23 +165,28 @@ servers and clients with optional TLS (for TCP) and optional application-layer e { Protocol = ProtocolType.TCP, Host = "127.0.0.1", - Port = 8080, - UseSsl = true, + Port = 1111, + UseSsl = false, UseAesEncryption = true, - ServerCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2("client.pfx", "p@ss"), + AesPassword = "EonaCat.Connections.Password", + //Certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2("client.pfx", "p@ss"), }; _client = new NetworkClient(config); // Subscribe to events _client.OnConnected += (sender, e) => + { Console.WriteLine($"Connected to server at {e.RemoteEndPoint}"); + }; _client.OnDataReceived += (sender, e) => Console.WriteLine($"Server says: {(e.IsBinary ? $"{e.Data.Length} bytes" : e.StringData)}"); _client.OnDisconnected += (sender, e) => + { Console.WriteLine("Disconnected from server"); + }; await _client.ConnectAsync(); @@ -175,4 +197,4 @@ servers and clients with optional TLS (for TCP) and optional application-layer e await _client.SendAsync("Hello server!"); } } - } \ No newline at end of file +} \ No newline at end of file