diff --git a/EonaCat.Network/EonaCat.Network.csproj b/EonaCat.Network/EonaCat.Network.csproj index 9c7f28c..8a29e46 100644 --- a/EonaCat.Network/EonaCat.Network.csproj +++ b/EonaCat.Network/EonaCat.Network.csproj @@ -18,9 +18,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.3 - 1.0.0.3 - 1.0.0.3 + 1.0.5 + 1.0.0.5 + 1.0.0.5 icon.png diff --git a/EonaCat.Network/System/Sockets/Client.cs b/EonaCat.Network/System/Sockets/Client.cs index dda9ab9..b45b8b3 100644 --- a/EonaCat.Network/System/Sockets/Client.cs +++ b/EonaCat.Network/System/Sockets/Client.cs @@ -26,7 +26,7 @@ namespace EonaCat.Sockets /// /// Buffer size /// - public static int BufferSize { get; set; } = 8 * 1024; // 8KB + public static int BufferSize { get; set; } = 1024 * 1024; // 1024KB /// /// Socket connection state. diff --git a/EonaCat.Network/System/Sockets/SocketServer.cs b/EonaCat.Network/System/Sockets/SocketServer.cs index b5693d4..6077249 100644 --- a/EonaCat.Network/System/Sockets/SocketServer.cs +++ b/EonaCat.Network/System/Sockets/SocketServer.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; +using System.Threading; using System.Threading.Tasks; using EonaCat.Helpers.Controls; @@ -35,7 +36,7 @@ namespace EonaCat.Sockets /// /// Interval to check for disconnected clients /// - public int DisconnectionCheckInterval { get; set; } = 100; + public int DisconnectionCheckInterval { get; set; } = 50; /// /// Determines if we need to reuse the socket address @@ -251,20 +252,18 @@ namespace EonaCat.Sockets /// public Socket CustomTcpSocket { get; set; } - static void SetConnectionReset(Socket socket) + private static void SetConnectionReset(Socket socket) { - try + if (socket.ProtocolType != ProtocolType.Udp || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (socket.ProtocolType == ProtocolType.Udp && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - // Disable ICMP packet shutdown (forcibly closed) - const uint IOC_IN = 0x80000000; - const uint IOC_VENDOR = 0x18000000; - uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; - socket.IOControl((int)SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null); - }; + return; } - catch { } + + // Disable ICMP packet shutdown (forcibly closed) + const uint IOC_IN = 0x80000000; + const uint IOC_VENDOR = 0x18000000; + uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12; + socket.IOControl((int)SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null); } private void ConfigureSocketOptions() @@ -313,18 +312,13 @@ namespace EonaCat.Sockets switch (ServerType) { case NetworkType.Tcp: - Server.BeginAccept(AcceptCallback, Server); + BeginTcpAccept(); break; case NetworkType.Udp: - var loopbackAddress = Server.AddressFamily == AddressFamily.InterNetworkV6 - ? IPAddress.IPv6Loopback - : IPAddress.Loopback; - - var buffer = new byte[Client.BufferSize]; - EndPoint remoteIp = new IPEndPoint(loopbackAddress, 0); - Server.BeginReceiveFrom(buffer, 0, Client.BufferSize, 0, ref remoteIp, UseClientManager ? AcceptClientsCallbackUDP : ReadClientCallbackUdp, new object[] { buffer, remoteIp, Server }); + BeginUdpReceive(); break; + default: throw new NotSupportedException("Protocol type not supported"); } @@ -335,6 +329,61 @@ namespace EonaCat.Sockets } } + private void BeginTcpAccept() + { + Server.BeginAccept(AcceptCallback, Server); + } + + private void BeginUdpReceive() + { + var loopbackAddress = Server.AddressFamily == AddressFamily.InterNetworkV6 + ? IPAddress.IPv6Loopback + : IPAddress.Loopback; + + var buffer = new byte[Client.BufferSize]; + EndPoint remoteIp = new IPEndPoint(loopbackAddress, 0); + Server.BeginReceiveFrom(buffer, 0, Client.BufferSize, 0, ref remoteIp, UseClientManager ? AcceptClientsCallbackUdp : ReadClientCallbackUdp, new object[] { buffer, remoteIp, Server }); + } + + private void ReadCallback(IAsyncResult ar) + { + try + { + var client = (Client)ar.AsyncState; + var bytesRead = client.Socket.EndReceive(ar); + if (bytesRead > 0) + { + var data = new byte[bytesRead]; + Array.Copy(client.Buffer, 0, data, 0, bytesRead); + OnReceived?.Invoke(this, new SocketServerDataEventArgs() { Client = client, Data = data }); + + // read any remaining data + while (client.Socket.Available > 0) + { + bytesRead = client.Socket.Receive(client.Buffer, 0, Client.BufferSize, SocketFlags.None); + data = new byte[bytesRead]; + Array.Copy(client.Buffer, 0, data, 0, bytesRead); + OnReceived?.Invoke(this, new SocketServerDataEventArgs() { Client = client, Data = data }); + } + + client.Socket.BeginReceive(client.Buffer, 0, Client.BufferSize, 0, ReadCallback, client); // recursive call + } + else + { + OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client }); + lock (ConnectedClients) + { + ConnectedClients.Remove(client); + } + } + } + catch (SocketException se) + { + OnError?.Invoke(this, new ErrorEventArgs(se)); + } + catch (ObjectDisposedException) { } + } + private void AcceptCallback(IAsyncResult ar) { try @@ -350,39 +399,27 @@ namespace EonaCat.Sockets { ConnectedClients.Add(client); } + OnConnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client }); - client.Socket.BeginReceive(client.Buffer, 0, Client.BufferSize, 0, ReadCallback, client); - listener.BeginAccept(AcceptCallback, Server); - } - catch (SocketException se) - { - OnError?.Invoke(this, new ErrorEventArgs(se)); - } - catch (ObjectDisposedException) { } - } + client.Socket.BeginReceive(client.Buffer, 0, Client.BufferSize, 0, ReadCallback, client); // recursive call - private void ReadCallback(IAsyncResult ar) - { - try - { - var client = (Client)ar.AsyncState; - var bytesRead = client.Socket.EndReceive(ar); - if (bytesRead > 0) + Thread.Sleep(DisconnectionCheckInterval); + + if (listener.IsBound) // check if the listener is still bound { - var data = new byte[bytesRead]; - Array.Copy(client.Buffer, 0, data, 0, bytesRead); - OnReceived?.Invoke(this, new SocketServerDataEventArgs() { Client = client, Data = data }); + listener.BeginAccept(AcceptCallback, Server); // recursive call } - client.Socket.BeginReceive(client.Buffer, 0, Client.BufferSize, 0, ReadCallback, client); } catch (SocketException se) { OnError?.Invoke(this, new ErrorEventArgs(se)); } - catch (ObjectDisposedException) { } + catch (ObjectDisposedException) + { + } } - private void AcceptClientsCallbackUDP(IAsyncResult ar) + private void AcceptClientsCallbackUdp(IAsyncResult ar) { try { @@ -413,7 +450,7 @@ namespace EonaCat.Sockets } } - if (bytesRead > 1) + if (bytesRead > 0) { var data = new byte[bytesRead]; Array.Copy(buffer, 0, data, 0, bytesRead); @@ -434,7 +471,7 @@ namespace EonaCat.Sockets } } - Server.BeginReceiveFrom(buffer, 0, Client.BufferSize, 0, ref remoteIp, AcceptClientsCallbackUDP, new object[] { buffer, remoteIp, listener }); + Server.BeginReceiveFrom(buffer, 0, Client.BufferSize, 0, ref remoteIp, AcceptClientsCallbackUdp, new object[] { buffer, remoteIp, listener }); } catch (SocketException se) { @@ -452,7 +489,7 @@ namespace EonaCat.Sockets var remoteIp = objects[1] as EndPoint; var listener = objects[2] as Socket; var bytesRead = listener.EndReceiveFrom(ar, ref remoteIp); - if (bytesRead > 0) + while (bytesRead > 0) { var data = new byte[bytesRead]; Array.Copy(buffer, 0, data, 0, bytesRead); @@ -465,8 +502,11 @@ namespace EonaCat.Sockets Socket = new Socket(remoteIp.AddressFamily, SocketType.Dgram, ProtocolType.Udp) } }); + + // read any remaining data + bytesRead = listener.ReceiveFrom(buffer, 0, Client.BufferSize, SocketFlags.None, ref remoteIp); } - Server.BeginReceiveFrom(buffer, 0, Client.BufferSize, 0, ref remoteIp, ReadClientCallbackUdp, new object[] { buffer, remoteIp, Server }); + listener.BeginReceiveFrom(buffer, 0, Client.BufferSize, 0, ref remoteIp, ReadClientCallbackUdp, new object[] { buffer, remoteIp, listener }); } catch (SocketException se) { @@ -475,24 +515,6 @@ namespace EonaCat.Sockets catch (ObjectDisposedException) { } } - private void DisconnectCallback(IAsyncResult ar) - { - try - { - var client = (Client)ar.AsyncState; - client.Socket.EndDisconnect(ar); - OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client }); - lock (ConnectedClients) - { - ConnectedClients.Remove(client); - } - } - catch (SocketException se) - { - OnError?.Invoke(this, new ErrorEventArgs(se)); - } - } - public void SendData(byte[] data, EndPoint point) { try