diff --git a/EonaCat.Network/EonaCat.Network.csproj b/EonaCat.Network/EonaCat.Network.csproj index 7efc785..698e847 100644 --- a/EonaCat.Network/EonaCat.Network.csproj +++ b/EonaCat.Network/EonaCat.Network.csproj @@ -3,8 +3,7 @@ Latest netstandard2.1; - net5.0; - net6.0; + net6.0; net7.0; true @@ -17,9 +16,9 @@ EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server EonaCat Networking library with Quic, TCP, UDP and a Webserver - 1.0.8 - 1.0.0.8 - 1.0.0.8 + 1.0.9 + 1.0.0.9 + 1.0.0.9 icon.png diff --git a/EonaCat.Network/NetworkHelper.cs b/EonaCat.Network/NetworkHelper.cs index befd61c..ddd847b 100644 --- a/EonaCat.Network/NetworkHelper.cs +++ b/EonaCat.Network/NetworkHelper.cs @@ -18,10 +18,19 @@ namespace EonaCat.Network internal static Logging Logger = new Logging(); private static QuicServer _quicServer; + /// + /// OnQuicClientConnected event + /// public static event EventHandler OnQuicClientConnected; + /// + /// OnQuicStreamOpened event + /// public static event EventHandler OnQuicStreamOpened; + /// + /// OnQuicStreamDataReceived event + /// public static event EventHandler OnQuicStreamDataReceived; /// @@ -60,6 +69,13 @@ namespace EonaCat.Network OnQuicStreamDataReceived?.Invoke(null, new QuicStreamEventArgs { Stream = stream, Data = data }); } + /// + /// Start a Quic client + /// + /// + /// + /// + /// public static QuicStream QuicStartClient(string ip, int port = 11000, StreamType streamType = StreamType.ClientBidirectional) { QuicClient client = new QuicClient(); diff --git a/EonaCat.Network/System/Sockets/Tcp/SocketTcpClient.cs b/EonaCat.Network/System/Sockets/Tcp/SocketTcpClient.cs index f637c61..af498b3 100644 --- a/EonaCat.Network/System/Sockets/Tcp/SocketTcpClient.cs +++ b/EonaCat.Network/System/Sockets/Tcp/SocketTcpClient.cs @@ -1,20 +1,45 @@ using System; +using System.ComponentModel; using System.Net; using System.Net.Sockets; using System.Threading.Tasks; namespace EonaCat.Network { + public class SocketTcpClient { + private const int BUFFER_SIZE = 4096; + + /// + /// OnConnect event + /// public event Action OnConnect; + + /// + /// OnReceive event + /// public event Action OnReceive; + + /// + /// OnDisconnect event + /// public event Action OnDisconnect; - public event Action OnSend; + + /// + /// OnError event + /// public event Action OnError; private Socket socket; + /// + /// Create TCP client + /// + /// + /// + /// + /// public Task ConnectAsync(string ipAddress, int port) { if (!IPAddress.TryParse(ipAddress, out IPAddress ip)) @@ -27,13 +52,13 @@ namespace EonaCat.Network private async Task CreateSocketTcpClientAsync(IPAddress ipAddress, int port) { - IsIP6 = ipAddress.AddressFamily == AddressFamily.InterNetworkV6; - socket = new Socket(IsIP6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + IsIp6 = ipAddress.AddressFamily == AddressFamily.InterNetworkV6; + socket = new Socket(IsIp6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { await socket.ConnectAsync(ipAddress, port).ConfigureAwait(false); - OnConnect?.Invoke(new RemoteInfo { IsTcp = true, IsIpv6 = IsIP6 }); - await StartReceivingAsync(); + OnConnect?.Invoke(new RemoteInfo { IsTcp = true, IsIpv6 = IsIp6 }); + _ = StartReceivingAsync(); } catch (SocketException ex) { @@ -42,11 +67,11 @@ namespace EonaCat.Network } } - public bool IsIP6 { get; private set; } + public bool IsIp6 { get; set; } private async Task StartReceivingAsync() { - byte[] buffer = new byte[1024]; + byte[] buffer = new byte[BUFFER_SIZE]; // Increased buffer size for better performance while (socket.Connected) { try @@ -54,13 +79,14 @@ namespace EonaCat.Network int received = await socket.ReceiveAsync(new ArraySegment(buffer), SocketFlags.None).ConfigureAwait(false); if (received > 0) { - byte[] data = buffer.AsSpan(0, received).ToArray(); + byte[] data = new byte[received]; + Buffer.BlockCopy(buffer, 0, data, 0, received); OnReceive?.Invoke(new RemoteInfo { IsTcp = true, Data = data, EndPoint = socket.RemoteEndPoint, - IsIpv6 = IsIP6 + IsIpv6 = socket.AddressFamily == AddressFamily.InterNetworkV6 }); } else @@ -74,15 +100,22 @@ namespace EonaCat.Network break; } } - OnDisconnect?.Invoke(new RemoteInfo { IsTcp = true, EndPoint = socket.RemoteEndPoint, IsIpv6 = IsIP6 }); + OnDisconnect?.Invoke(new RemoteInfo { IsTcp = true, EndPoint = socket.RemoteEndPoint, IsIpv6 = socket.AddressFamily == AddressFamily.InterNetworkV6 }); } - public async Task SendAsync(byte[] data) + /// + /// Send data + /// + /// + /// + public Task SendAsync(byte[] data) { - await socket.SendAsync(new ArraySegment(data), SocketFlags.None).ConfigureAwait(false); - OnSend?.Invoke(new RemoteInfo { EndPoint = socket.RemoteEndPoint, Data = data, IsIpv6 = IsIP6 }); + return socket.SendAsync(new ArraySegment(data), SocketFlags.None); } + /// + /// Disconnect + /// public void Disconnect() { socket.Close(); diff --git a/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs b/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs index 296cebf..62811a8 100644 --- a/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs +++ b/EonaCat.Network/System/Sockets/Tcp/SocketTcpServer.cs @@ -8,41 +8,79 @@ namespace EonaCat.Network { public class SocketTcpServer { + private const int BUFFER_SIZE = 4096; + + /// + /// OnConnect event + /// public event Action OnConnect; + + /// + /// OnReceive event + /// public event Action OnReceive; + + /// + /// OnSend event + /// public event Action OnSend; + + /// + /// OnDisconnect event + /// public event Action OnDisconnect; + + /// + /// OnError event + /// public event Action OnError; - private TcpListener listener; + private readonly TcpListener _listener; + private CancellationTokenSource _cancellationTokenSource; + private Task _acceptTask; + /// + /// Create TCP server + /// + /// + /// public SocketTcpServer(IPAddress ipAddress, int port) { - listener = new TcpListener(ipAddress, port); + _listener = new TcpListener(ipAddress, port); } + /// + /// Create TCP server + /// + /// + /// public SocketTcpServer(string ipAddress, int port) { IPAddress address = IPAddress.Parse(ipAddress); - listener = new TcpListener(address, port); + _listener = new TcpListener(address, port); } - public async Task StartAsync(CancellationToken cancellationToken = default) + /// + /// Start TCP server + /// + /// + /// + public Task StartAsync(CancellationToken cancellationToken = default) + { + _listener.Start(); + _cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + _acceptTask = AcceptConnectionsAsync(_cancellationTokenSource.Token); + return _acceptTask; + } + + private async Task AcceptConnectionsAsync(CancellationToken cancellationToken) { - listener.Start(); while (!cancellationToken.IsCancellationRequested) { try { - Socket socket = await listener.AcceptSocketAsync().ConfigureAwait(false); - OnConnect?.Invoke(new RemoteInfo - { - Socket = socket, - IsTcp = true, - IsIpv6 = socket.RemoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6, - EndPoint = socket.RemoteEndPoint - }); - await StartReceivingAsync(socket, cancellationToken).ConfigureAwait(false); + var socket = await _listener.AcceptSocketAsync().ConfigureAwait(false); + _ = HandleConnectionAsync(socket, cancellationToken); } catch (SocketException ex) { @@ -51,24 +89,33 @@ namespace EonaCat.Network } } - private async Task StartReceivingAsync(Socket socket, CancellationToken cancellationToken) + private async Task HandleConnectionAsync(Socket socket, CancellationToken cancellationToken) { - byte[] buffer = new byte[1024]; + OnConnect?.Invoke(new RemoteInfo + { + Socket = socket, + IsTcp = true, + IsIpv6 = socket.AddressFamily == AddressFamily.InterNetworkV6, + EndPoint = socket.RemoteEndPoint + }); + + byte[] buffer = new byte[BUFFER_SIZE]; while (!cancellationToken.IsCancellationRequested) { try { - int received = await socket.ReceiveAsync(new Memory(buffer), SocketFlags.None, cancellationToken) - .ConfigureAwait(false); + int received = await socket.ReceiveAsync(new Memory(buffer), SocketFlags.None, cancellationToken).ConfigureAwait(false); if (received > 0) { + byte[] data = new byte[received]; + Buffer.BlockCopy(buffer, 0, data, 0, received); OnReceive?.Invoke(new RemoteInfo { Socket = socket, IsTcp = true, - IsIpv6 = socket.RemoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6, + IsIpv6 = socket.AddressFamily == AddressFamily.InterNetworkV6, EndPoint = socket.RemoteEndPoint, - Data = new Memory(buffer, 0, received).ToArray() + Data = data }); } else @@ -82,12 +129,51 @@ namespace EonaCat.Network break; } } + + OnDisconnect?.Invoke(new RemoteInfo + { + Socket = socket, + IsTcp = true, + EndPoint = socket.RemoteEndPoint, + IsIpv6 = socket.AddressFamily == AddressFamily.InterNetworkV6 + }); } - public async Task SendTo(Socket socket, byte[] data) + /// + /// Send data to socket + /// + /// + /// + /// + public async Task SendToAsync(Socket socket, byte[] data) { await socket.SendAsync(new ArraySegment(data), SocketFlags.None).ConfigureAwait(false); - OnSend?.Invoke(new RemoteInfo { Socket = socket, IsTcp = true, EndPoint = socket.RemoteEndPoint, IsIpv6 = socket.RemoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6, Data = data }); + OnSend?.Invoke(new RemoteInfo + { + Socket = socket, + IsTcp = true, + EndPoint = socket.RemoteEndPoint, + IsIpv6 = socket.AddressFamily == AddressFamily.InterNetworkV6, + Data = data + }); + } + + /// + /// Stop TCP server + /// + /// + public async Task StopAsync() + { + _cancellationTokenSource.Cancel(); + _listener.Stop(); + if (_acceptTask != null) + { + try + { + await _acceptTask.ConfigureAwait(false); + } + catch (AggregateException) { } + } } } } \ No newline at end of file diff --git a/EonaCat.Network/System/Sockets/Udp/SocketUdpClient.cs b/EonaCat.Network/System/Sockets/Udp/SocketUdpClient.cs index ad40b1c..cbb52f1 100644 --- a/EonaCat.Network/System/Sockets/Udp/SocketUdpClient.cs +++ b/EonaCat.Network/System/Sockets/Udp/SocketUdpClient.cs @@ -8,14 +8,39 @@ namespace EonaCat.Network { public class SocketUdpClient { + /// + /// OnConnect event + /// public event Action OnConnect; + + /// + /// OnReceive event + /// public event Action OnReceive; + + /// + /// OnDisconnect event + /// public event Action OnDisconnect; + + /// + /// OnSend event + /// public event Action OnSend; + + /// + /// OnError event + /// public event Action OnError; - private UdpClient udpClient; + private UdpClient _udpClient; + /// + /// Create UDP client + /// + /// + /// + /// public SocketUdpClient(IPAddress ipAddress, int port, CancellationToken cancellationToken = default) { CreateUdpClient(ipAddress, port, cancellationToken); @@ -23,45 +48,36 @@ namespace EonaCat.Network private void CreateUdpClient(IPAddress ipAddress, int port, CancellationToken cancellationToken = default) { - IsIP6 = ipAddress.AddressFamily == AddressFamily.InterNetworkV6; - udpClient = new UdpClient(ipAddress.AddressFamily); + IsIp6 = ipAddress.AddressFamily == AddressFamily.InterNetworkV6; + _udpClient = new UdpClient(ipAddress.AddressFamily); - if (IsIP6) + if (IsIp6) { - udpClient.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); + _udpClient.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); } - udpClient.Client.Bind(new IPEndPoint(IsIP6 ? IPAddress.IPv6Any : IPAddress.Any, 0)); + _udpClient.Client.Bind(new IPEndPoint(IsIp6 ? IPAddress.IPv6Any : IPAddress.Any, 0)); if (IsMulticastGroupEnabled) { - udpClient.JoinMulticastGroup(ipAddress); + _udpClient.JoinMulticastGroup(ipAddress); } + OnConnect?.Invoke(_udpClient.Client.RemoteEndPoint); _ = StartReceivingAsync(cancellationToken); } public bool IsMulticastGroupEnabled { get; set; } - public bool IsIP6 { get; private set; } + public bool IsIp6 { get; private set; } - public SocketUdpClient(string ipAddress, int port) - { - if (!IPAddress.TryParse(ipAddress, out IPAddress ip)) - { - throw new Exception("Invalid ipAddress given"); - } - - CreateUdpClient(ip, port); - } - - private async Task StartReceivingAsync(CancellationToken cancellationToken = default) + private async Task StartReceivingAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { try { - UdpReceiveResult result = await udpClient.ReceiveAsync().ConfigureAwait(false); + var result = await _udpClient.ReceiveAsync().ConfigureAwait(false); OnReceive?.Invoke(result.Buffer); } catch (SocketException ex) @@ -70,21 +86,30 @@ namespace EonaCat.Network break; } } - OnDisconnect?.Invoke(udpClient.Client.RemoteEndPoint); + OnDisconnect?.Invoke(_udpClient.Client.RemoteEndPoint); } + /// + /// Send data to endPoint + /// + /// + /// + /// public async Task SendTo(EndPoint endPoint, byte[] data) { if (endPoint is IPEndPoint ipEndPoint) { - await udpClient.SendAsync(data, data.Length, ipEndPoint).ConfigureAwait(false); + await _udpClient.SendAsync(data, data.Length, ipEndPoint).ConfigureAwait(false); OnSend?.Invoke(endPoint, data); } } + /// + /// Disconnect UDP client + /// public void Disconnect() { - udpClient.Close(); + _udpClient.Close(); } } } diff --git a/EonaCat.Network/System/Sockets/Udp/SocketUdpServer.cs b/EonaCat.Network/System/Sockets/Udp/SocketUdpServer.cs index 5f42a5a..263723f 100644 --- a/EonaCat.Network/System/Sockets/Udp/SocketUdpServer.cs +++ b/EonaCat.Network/System/Sockets/Udp/SocketUdpServer.cs @@ -10,21 +10,49 @@ namespace EonaCat.Network { public class SocketUdpServer { + /// + /// OnReceive event + /// public event Action OnReceive; + + /// + /// OnSend event + /// public event Action OnSend; + + /// + /// OnError event + /// public event Action OnError; + + /// + /// OnDisconnect event + /// public event Action OnDisconnect; - private UdpClient udpClient; - public bool IsIP6 { get; private set; } + /// + /// Determines if the UDP server is IpV6 + /// + public bool IsIp6 { get; private set; } + /// + /// Create UDP server + /// + /// + /// public SocketUdpServer(IPAddress ipAddress, int port) { CreateUdpServer(ipAddress, port); } + /// + /// Create UDP server + /// + /// + /// + /// public SocketUdpServer(string ipAddress, int port) { if (!IPAddress.TryParse(ipAddress, out IPAddress ip)) @@ -35,7 +63,6 @@ namespace EonaCat.Network CreateUdpServer(ip, port); } - private static void SetConnectionReset(Socket socket) { if (socket.ProtocolType != ProtocolType.Udp && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) @@ -52,11 +79,11 @@ namespace EonaCat.Network private void CreateUdpServer(IPAddress ipAddress, int port) { - IsIP6 = ipAddress.AddressFamily == AddressFamily.InterNetworkV6; + IsIp6 = ipAddress.AddressFamily == AddressFamily.InterNetworkV6; udpClient = new UdpClient(ipAddress.AddressFamily); SetConnectionReset(udpClient.Client); - - if (IsIP6) + + if (IsIp6) { udpClient.Client.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); } @@ -64,13 +91,18 @@ namespace EonaCat.Network udpClient.Client.Bind(new IPEndPoint(ipAddress, port)); } + /// + /// Start UDP server + /// + /// + /// public async Task StartAsync(CancellationToken cancellationToken = default) { while (!cancellationToken.IsCancellationRequested) { try { - UdpReceiveResult result = await udpClient.ReceiveAsync().ConfigureAwait(false); + var result = await udpClient.ReceiveAsync().ConfigureAwait(false); OnReceive?.Invoke(new RemoteInfo() { EndPoint = result.RemoteEndPoint, @@ -85,6 +117,12 @@ namespace EonaCat.Network } } + /// + /// Send data to endPoint + /// + /// + /// + /// public async Task SendToAsync(EndPoint endPoint, byte[] data) { if (endPoint is IPEndPoint ipEndPoint) @@ -94,15 +132,21 @@ namespace EonaCat.Network } } + /// + /// Send data to all clients + /// + /// + /// public async Task SendToAllAsync(byte[] data) { // get all connected clients - IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties(); - IPEndPoint[] endPoints = ipProperties.GetActiveUdpListeners(); - foreach (IPEndPoint endPoint in endPoints) + var ipProperties = IPGlobalProperties.GetIPGlobalProperties(); + var endPoints = ipProperties.GetActiveUdpListeners(); + foreach (var endPoint in endPoints) { await udpClient.SendAsync(data, data.Length, endPoint).ConfigureAwait(false); } } } + }