diff --git a/EonaCat.Network/EonaCat.Network.csproj b/EonaCat.Network/EonaCat.Network.csproj
index 60c089c..9c7f28c 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.2
- 1.0.0.2
- 1.0.0.2
+ 1.0.3
+ 1.0.0.3
+ 1.0.0.3
icon.png
@@ -50,6 +50,7 @@
+
diff --git a/EonaCat.Network/System/Sockets/ClientConnection.cs b/EonaCat.Network/System/Sockets/Client.cs
similarity index 92%
rename from EonaCat.Network/System/Sockets/ClientConnection.cs
rename to EonaCat.Network/System/Sockets/Client.cs
index 7293580..dda9ab9 100644
--- a/EonaCat.Network/System/Sockets/ClientConnection.cs
+++ b/EonaCat.Network/System/Sockets/Client.cs
@@ -6,7 +6,7 @@ namespace EonaCat.Sockets
{
public delegate void SendBytesTo(byte[] data, EndPoint point);
- public class ClientConnection : IDisposable
+ public class Client : IDisposable
{
///
/// Unique client id.
@@ -43,10 +43,7 @@ namespace EonaCat.Sockets
public event SendBytesTo SendData;
- ///
- /// ClientConnection class constructor.
- ///
- public ClientConnection()
+ public Client()
{
Buffer = new byte[BufferSize];
}
diff --git a/EonaCat.Network/System/Sockets/SocketClient.cs b/EonaCat.Network/System/Sockets/SocketClient.cs
index 00dceb3..8e05950 100644
--- a/EonaCat.Network/System/Sockets/SocketClient.cs
+++ b/EonaCat.Network/System/Sockets/SocketClient.cs
@@ -5,7 +5,7 @@ using System.Net.Sockets;
namespace EonaCat.Sockets
{
- public class SocketClient : ClientConnection, IDisposable
+ public class SocketClient : Client, IDisposable
{
///
/// Client type
diff --git a/EonaCat.Network/System/Sockets/SocketServer.cs b/EonaCat.Network/System/Sockets/SocketServer.cs
index 796d5dd..b5693d4 100644
--- a/EonaCat.Network/System/Sockets/SocketServer.cs
+++ b/EonaCat.Network/System/Sockets/SocketServer.cs
@@ -5,7 +5,8 @@ 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;
namespace EonaCat.Sockets
{
@@ -29,7 +30,7 @@ namespace EonaCat.Sockets
///
/// List of connected clients.
///
- public List ConnectedClients { get; set; } = new List();
+ public List ConnectedClients { get; set; } = new List();
///
/// Interval to check for disconnected clients
@@ -44,9 +45,8 @@ namespace EonaCat.Sockets
///
/// Determines if the socket is in blocking mode
- /// (default: true)
///
- public bool IsSocketInBlockingMode { get; set; } = true;
+ public bool IsSocketBlockingDisabled { get; set; }
///
@@ -60,9 +60,9 @@ namespace EonaCat.Sockets
///
/// Only for UDP.
- /// Required to use SocketClient class for this.
+ /// (default: true)
///
- public bool UDPClientManage { get; set; } = true;
+ public bool UseClientManager { get; set; } = true;
///
/// Only for UDP.
@@ -96,18 +96,20 @@ namespace EonaCat.Sockets
///
public event EventHandler OnStop;
- private Socket Listener { get; set; }
- private System.Timers.Timer DisconnectTimer { get; set; }
+ private Socket Server { get; set; }
+ private EonaCatTimer DisconnectTimerUdp { get; set; }
+ private EonaCatTimer DisconnectTimerTcp { get; set; }
private Dictionary LastDataReceivedTime { get; set; }
private double TimeNow { get => (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
public SocketServer(NetworkType type, string address, int port)
{
- if (IPAddress.TryParse(address, out var ipAddress))
+ if (!IPAddress.TryParse(address, out var ipAddress))
{
- new SocketServer(type, ipAddress, port);
+ throw new Exception("Invalid IP address specified");
}
- throw new Exception("Invalid IP address specified");
+
+ SetupSocketServer(type, ipAddress, port);
}
///
@@ -117,12 +119,63 @@ namespace EonaCat.Sockets
/// Server listening ip
/// Server listening port
public SocketServer(NetworkType type, IPAddress address, int port)
+ {
+ SetupSocketServer(type, address, port);
+ }
+
+ private void SetupSocketServer(NetworkType type, IPAddress address, int port)
{
Guid = System.Guid.NewGuid().ToString();
ServerType = type;
IPAddress = address;
Port = port;
- DisconnectTimer = new System.Timers.Timer(DisconnectionCheckInterval);
+ }
+
+ private readonly List _removedEndpoints = new List();
+
+ private void UdpCheckCallback()
+ {
+ _removedEndpoints.Clear();
+ var now = TimeNow;
+ foreach (var kp in LastDataReceivedTime.Where(kp => now - kp.Value > _UDPDataInterval / 1000))
+ {
+ lock (ConnectedClients)
+ {
+ var client = ConnectedClients.FirstOrDefault(x => x.Guid == kp.Key.ToString());
+ if (client == null)
+ {
+ continue;
+ }
+ OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
+ ConnectedClients.Remove(client);
+ _removedEndpoints.Add(kp.Key);
+ }
+ }
+
+ lock (LastDataReceivedTime)
+ {
+ foreach (var r in _removedEndpoints)
+ {
+ LastDataReceivedTime.Remove(r);
+ }
+ }
+ }
+
+ private void TcpCheckCallback()
+ {
+ lock (ConnectedClients)
+ {
+ ConnectedClients.RemoveAll(x =>
+ {
+ if (x.IsConnected)
+ {
+ return false;
+ }
+
+ OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = x });
+ return true;
+ });
+ }
}
public void Dispose()
@@ -133,96 +186,52 @@ namespace EonaCat.Sockets
///
/// Start server
///
- public void Start()
+ public async Task StartAsync()
{
try
{
switch (ServerType)
{
case NetworkType.Tcp:
- Listener = new Socket(IPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
+ Server = new Socket(IPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
ConfigureSocketOptions();
// Check if we need to override the socket with a custom socket
if (CustomTcpSocket != null)
{
- Listener = CustomTcpSocket;
+ Server = CustomTcpSocket;
}
- DisconnectTimer.Elapsed += (s, e) =>
- {
- lock (ConnectedClients)
- {
- ConnectedClients.RemoveAll(x =>
- {
- if (x.IsConnected)
- {
- return false;
- }
-
- OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = x });
- return true;
- });
- }
- };
+ DisconnectTimerTcp = new EonaCatTimer(TimeSpan.FromMilliseconds(DisconnectionCheckInterval), TcpCheckCallback);
+ DisconnectTimerTcp.Start();
break;
case NetworkType.Udp:
{
- if (UDPClientManage)
+ if (UseClientManager)
{
LastDataReceivedTime = new Dictionary();
- DisconnectTimer.Elapsed += (s, e) =>
- {
- var now = TimeNow;
- var times = LastDataReceivedTime;
- var removed = new List();
- foreach (var kp in times)
- {
- if (now - kp.Value > _UDPDataInterval / 1000)
- {
- lock (ConnectedClients)
- {
- var client = ConnectedClients.Where(x => x.Guid == kp.Key.ToString());
- if (!client.Any())
- {
- continue;
- }
- OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client.First() });
- ConnectedClients.Remove(client.First());
- removed.Add(kp.Key);
- }
- }
- }
- lock (LastDataReceivedTime)
- {
- foreach (var r in removed)
- {
- LastDataReceivedTime.Remove(r);
- }
- }
- };
+ DisconnectTimerUdp = new EonaCatTimer(TimeSpan.FromMilliseconds(DisconnectionCheckInterval), UdpCheckCallback);
+ DisconnectTimerUdp.Start();
}
- Listener = new Socket(IPAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
+ Server = new Socket(IPAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
ConfigureSocketOptions();
// Check if we need to override the socket with a custom socket
if (CustomUdpSocket != null)
{
- Listener = CustomUdpSocket;
+ Server = CustomUdpSocket;
}
-
break;
}
}
- Listener.ReceiveBufferSize = ClientConnection.BufferSize;
- Listener.SendBufferSize = ClientConnection.BufferSize;
- Listener.Bind(new IPEndPoint(IPAddress, Port));
+ Server.ReceiveBufferSize = Client.BufferSize;
+ Server.SendBufferSize = Client.BufferSize;
+ Server.Bind(new IPEndPoint(IPAddress, Port));
if (ServerType == NetworkType.Tcp)
{
- Listener.Listen(Backlog);
+ Server.Listen(Backlog);
}
- DisconnectTimer.Start();
- ListenerLoop();
+ await Task.Run(ListenLoop);
}
catch (SocketException se)
{
@@ -261,14 +270,14 @@ namespace EonaCat.Sockets
private void ConfigureSocketOptions()
{
// Disable ICMP packet shutdown
- SetConnectionReset(Listener);
+ SetConnectionReset(Server);
if (ReuseAddress)
{
- Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+ Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
}
- Listener.Blocking = IsSocketInBlockingMode;
+ Server.Blocking = IsSocketBlockingDisabled;
}
///
@@ -278,7 +287,8 @@ namespace EonaCat.Sockets
{
try
{
- DisconnectTimer.Stop();
+ DisconnectTimerUdp?.Stop();
+ DisconnectTimerTcp?.Stop();
foreach (var client in ConnectedClients)
{
OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
@@ -286,7 +296,7 @@ namespace EonaCat.Sockets
}
ConnectedClients.Clear();
OnStop?.Invoke(this, EventArgs.Empty);
- Listener.Close();
+ Server.Close();
}
catch (SocketException socketException)
{
@@ -294,35 +304,29 @@ namespace EonaCat.Sockets
}
}
- private void ListenerLoop()
+ private void ListenLoop()
{
try
{
OnStart?.Invoke(this, CustomTcpSocket != null || CustomUdpSocket != null ? "Custom socket was used" : string.Empty);
- if (ServerType == NetworkType.Tcp)
- {
- Listener.BeginAccept(AcceptCallback, Listener);
- }
- if (ServerType != NetworkType.Udp)
+ switch (ServerType)
{
- return;
- }
- var loopbackAddress = Listener.AddressFamily == AddressFamily.InterNetworkV6
- ? IPAddress.IPv6Loopback
- : IPAddress.Loopback;
+ case NetworkType.Tcp:
+ Server.BeginAccept(AcceptCallback, Server);
+ break;
- if (UDPClientManage)
- {
- var buffer = new byte[ClientConnection.BufferSize];
- EndPoint remoteIp = new IPEndPoint(loopbackAddress, 0);
- Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteIp, AcceptCallbackUDP, new object[] { buffer, remoteIp, Listener });
- }
- else
- {
- var buffer = new byte[ClientConnection.BufferSize];
- EndPoint remoteEp = new IPEndPoint(loopbackAddress, 0);
- Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteEp, ReadCallbackUDP, new object[] { buffer, remoteEp, Listener });
+ 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 });
+ break;
+ default:
+ throw new NotSupportedException("Protocol type not supported");
}
}
catch (SocketException se)
@@ -337,7 +341,7 @@ namespace EonaCat.Sockets
{
var listener = (Socket)ar.AsyncState;
var handler = listener.EndAccept(ar);
- var client = new ClientConnection()
+ var client = new Client()
{
Guid = System.Guid.NewGuid().ToString(),
Socket = handler
@@ -347,8 +351,8 @@ namespace EonaCat.Sockets
ConnectedClients.Add(client);
}
OnConnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
- client.Socket.BeginReceive(client.Buffer, 0, ClientConnection.BufferSize, 0, ReadCallback, client);
- listener.BeginAccept(AcceptCallback, Listener);
+ client.Socket.BeginReceive(client.Buffer, 0, Client.BufferSize, 0, ReadCallback, client);
+ listener.BeginAccept(AcceptCallback, Server);
}
catch (SocketException se)
{
@@ -361,7 +365,7 @@ namespace EonaCat.Sockets
{
try
{
- var client = (ClientConnection)ar.AsyncState;
+ var client = (Client)ar.AsyncState;
var bytesRead = client.Socket.EndReceive(ar);
if (bytesRead > 0)
{
@@ -369,8 +373,7 @@ namespace EonaCat.Sockets
Array.Copy(client.Buffer, 0, data, 0, bytesRead);
OnReceived?.Invoke(this, new SocketServerDataEventArgs() { Client = client, Data = data });
}
- Thread.Sleep(DisconnectionCheckInterval);
- client.Socket.BeginReceive(client.Buffer, 0, ClientConnection.BufferSize, 0, ReadCallback, client);
+ client.Socket.BeginReceive(client.Buffer, 0, Client.BufferSize, 0, ReadCallback, client);
}
catch (SocketException se)
{
@@ -379,7 +382,7 @@ namespace EonaCat.Sockets
catch (ObjectDisposedException) { }
}
- private void AcceptCallbackUDP(IAsyncResult ar)
+ private void AcceptClientsCallbackUDP(IAsyncResult ar)
{
try
{
@@ -388,27 +391,28 @@ namespace EonaCat.Sockets
var remoteIp = objects[1] as EndPoint;
var listener = objects[2] as Socket;
var bytesRead = listener.EndReceiveFrom(ar, ref remoteIp);
- var clients = ConnectedClients.Where(x => x.Guid == remoteIp.ToString()).ToList();
- ClientConnection client;
- if (clients.Count == 0)
+
+ Client client;
+ lock (ConnectedClients)
{
- client = new ClientConnection()
+ client = ConnectedClients.FirstOrDefault(x => x.Guid == remoteIp.ToString());
+ if (client == null)
{
- Guid = remoteIp.ToString(),
- Socket = new Socket(remoteIp.AddressFamily, SocketType.Dgram, ProtocolType.Udp)
- };
- client.SendData += SendData;
- client.Socket.Connect(remoteIp);
- if (client.IsConnected)
- {
- ConnectedClients.Add(client);
- OnConnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
+ client = new Client()
+ {
+ Guid = remoteIp.ToString(),
+ Socket = new Socket(remoteIp.AddressFamily, SocketType.Dgram, ProtocolType.Udp)
+ };
+ client.SendData += SendData;
+ client.Socket.Connect(remoteIp);
+ if (client.IsConnected)
+ {
+ ConnectedClients.Add(client);
+ OnConnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
+ }
}
}
- else
- {
- client = clients.First();
- }
+
if (bytesRead > 1)
{
var data = new byte[bytesRead];
@@ -417,16 +421,20 @@ namespace EonaCat.Sockets
}
else
{
- if (LastDataReceivedTime.ContainsKey(remoteIp))
+ lock (LastDataReceivedTime)
{
- LastDataReceivedTime[remoteIp] = TimeNow;
- }
- else
- {
- LastDataReceivedTime.Add(remoteIp, TimeNow);
+ if (LastDataReceivedTime.ContainsKey(remoteIp))
+ {
+ LastDataReceivedTime[remoteIp] = TimeNow;
+ }
+ else
+ {
+ LastDataReceivedTime.Add(remoteIp, TimeNow);
+ }
}
}
- Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteIp, AcceptCallbackUDP, new object[] { buffer, remoteIp, Listener });
+
+ Server.BeginReceiveFrom(buffer, 0, Client.BufferSize, 0, ref remoteIp, AcceptClientsCallbackUDP, new object[] { buffer, remoteIp, listener });
}
catch (SocketException se)
{
@@ -435,22 +443,30 @@ namespace EonaCat.Sockets
catch (ObjectDisposedException) { }
}
- private void ReadCallbackUDP(IAsyncResult ar)
+ private void ReadClientCallbackUdp(IAsyncResult ar)
{
try
{
var objects = (object[])ar.AsyncState;
var buffer = objects[0] as byte[];
- var remote_ip = objects[1] as EndPoint;
+ var remoteIp = objects[1] as EndPoint;
var listener = objects[2] as Socket;
- var bytesRead = listener.EndReceiveFrom(ar, ref remote_ip);
+ var bytesRead = listener.EndReceiveFrom(ar, ref remoteIp);
if (bytesRead > 0)
{
var data = new byte[bytesRead];
Array.Copy(buffer, 0, data, 0, bytesRead);
- OnReceived?.Invoke(this, new SocketServerDataEventArgs() { Data = data });
+ OnReceived?.Invoke(this, new SocketServerDataEventArgs()
+ {
+ Data = data,
+ Client = new Client()
+ {
+ Guid = remoteIp.ToString(),
+ Socket = new Socket(remoteIp.AddressFamily, SocketType.Dgram, ProtocolType.Udp)
+ }
+ });
}
- Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remote_ip, ReadCallbackUDP, new object[] { buffer, remote_ip, Listener });
+ Server.BeginReceiveFrom(buffer, 0, Client.BufferSize, 0, ref remoteIp, ReadClientCallbackUdp, new object[] { buffer, remoteIp, Server });
}
catch (SocketException se)
{
@@ -463,7 +479,7 @@ namespace EonaCat.Sockets
{
try
{
- var client = (ClientConnection)ar.AsyncState;
+ var client = (Client)ar.AsyncState;
client.Socket.EndDisconnect(ar);
OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
lock (ConnectedClients)
@@ -481,7 +497,7 @@ namespace EonaCat.Sockets
{
try
{
- Listener.BeginSendTo(data, 0, data.Length, 0, point, EndSendTo, null);
+ Server.BeginSendTo(data, 0, data.Length, 0, point, EndSendTo, null);
}
catch (SocketException se)
{
@@ -493,7 +509,7 @@ namespace EonaCat.Sockets
{
try
{
- Listener.EndSendTo(ar);
+ Server.EndSendTo(ar);
}
catch (SocketException se)
{
diff --git a/EonaCat.Network/System/Sockets/SocketServerEventArgs.cs b/EonaCat.Network/System/Sockets/SocketServerEventArgs.cs
index c874af9..ac64e80 100644
--- a/EonaCat.Network/System/Sockets/SocketServerEventArgs.cs
+++ b/EonaCat.Network/System/Sockets/SocketServerEventArgs.cs
@@ -5,11 +5,12 @@ namespace EonaCat.Sockets
public class SocketServerDataEventArgs : EventArgs
{
///
- /// Client connection.
+ /// Client.
///
- public ClientConnection Client { get; set; }
+ public Client Client { get; set; }
+
///
- /// Recieved data.
+ /// Received data.
///
public byte[] Data { get; set; }
}
@@ -19,6 +20,6 @@ namespace EonaCat.Sockets
///
/// Client connection.
///
- public ClientConnection Client { get; set; }
+ public Client Client { get; set; }
}
}
diff --git a/EonaCat.Network/System/Sockets/SocketServerPool.cs b/EonaCat.Network/System/Sockets/SocketServerPool.cs
deleted file mode 100644
index a149c5a..0000000
--- a/EonaCat.Network/System/Sockets/SocketServerPool.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-
-namespace EonaCat.Sockets
-{
- public class SocketServerPool : IDisposable
- {
- public List Servers { get; set; } = new List();
-
- public SocketServer this[int index]
- {
- get
- {
- if (Servers.Count < index)
- return Servers[index];
- return null;
- }
- }
- public SocketServer this[string name]
- {
- get
- {
- var server = Servers.Where(x => x.Guid == name);
- if (server.Count() > 0)
- return server.First();
- return null;
- }
- }
-
- public void Dispose()
- {
- Servers.ForEach(x => x.Stop());
- Servers.Clear();
- }
-
- public SocketServer Add(NetworkType type, IPAddress ip, int port)
- {
- SocketServer server = new SocketServer(type, ip, port);
- Servers.Add(server);
- return server;
- }
-
- public bool Remove(string name)
- {
- int count = Servers.RemoveAll(x => x.Guid == name);
- return count > 0 ? true : false;
- }
-
- public bool Remove(int index)
- {
- try
- {
- Servers.RemoveAt(index);
- }
- catch
- {
- return false;
- }
- return true;
- }
- }
-}