diff --git a/EonaCat.Network/EonaCat.Network.csproj b/EonaCat.Network/EonaCat.Network.csproj
index 1aae10a..60c089c 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.1
- 1.0.0.1
- 1.0.0.1
+ 1.0.2
+ 1.0.0.2
+ 1.0.0.2
icon.png
diff --git a/EonaCat.Network/System/Sockets/SocketServer.cs b/EonaCat.Network/System/Sockets/SocketServer.cs
index 726ff7b..796d5dd 100644
--- a/EonaCat.Network/System/Sockets/SocketServer.cs
+++ b/EonaCat.Network/System/Sockets/SocketServer.cs
@@ -4,13 +4,11 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
+using System.Runtime.InteropServices;
using System.Threading;
namespace EonaCat.Sockets
{
- ///
- ///
- ///
public class SocketServer : IDisposable
{
///
@@ -38,6 +36,19 @@ namespace EonaCat.Sockets
///
public int DisconnectionCheckInterval { get; set; } = 100;
+ ///
+ /// Determines if we need to reuse the socket address
+ /// (default: false)
+ ///
+ public bool ReuseAddress { get; set; }
+
+ ///
+ /// Determines if the socket is in blocking mode
+ /// (default: true)
+ ///
+ public bool IsSocketInBlockingMode { get; set; } = true;
+
+
///
/// Socket backlog. The maximum length of the pending connections queue.
///
@@ -48,12 +59,14 @@ namespace EonaCat.Sockets
public NetworkType ServerType { get; set; }
///
- /// Only for UDP. Require to use SocketClient class for this.
+ /// Only for UDP.
+ /// Required to use SocketClient class for this.
///
public bool UDPClientManage { get; set; } = true;
///
- /// Only for UDP. Accept 1 byte data for check connected state.
+ /// Only for UDP.
+ /// Accept 1 byte data for connected state check.
///
private int _UDPDataInterval { get => (int)(UDPDataInterval * 1.5); }
public int UDPDataInterval { get; set; } = 5000;
@@ -77,7 +90,7 @@ namespace EonaCat.Sockets
///
/// Called when executing Start() function
///
- public event EventHandler OnStart;
+ public event EventHandler OnStart;
///
/// Called when executing Stop() function
///
@@ -85,7 +98,7 @@ namespace EonaCat.Sockets
private Socket Listener { get; set; }
private System.Timers.Timer DisconnectTimer { get; set; }
- private Dictionary LastDataRecievedTime { 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)
@@ -128,6 +141,14 @@ namespace EonaCat.Sockets
{
case NetworkType.Tcp:
Listener = 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;
+ }
+
DisconnectTimer.Elapsed += (s, e) =>
{
lock (ConnectedClients)
@@ -146,44 +167,52 @@ namespace EonaCat.Sockets
};
break;
case NetworkType.Udp:
- {
- if (UDPClientManage)
{
- LastDataRecievedTime = new Dictionary();
- DisconnectTimer.Elapsed += (s, e) =>
+ if (UDPClientManage)
{
- var now = TimeNow;
- var times = LastDataRecievedTime;
- var removed = new List();
- foreach (var kp in times)
+ LastDataReceivedTime = new Dictionary();
+ DisconnectTimer.Elapsed += (s, e) =>
{
- if (now - kp.Value > _UDPDataInterval / 1000)
+ var now = TimeNow;
+ var times = LastDataReceivedTime;
+ var removed = new List();
+ foreach (var kp in times)
{
- lock (ConnectedClients)
+ if (now - kp.Value > _UDPDataInterval / 1000)
{
- var client = ConnectedClients.Where(x => x.Guid == kp.Key.ToString());
- if (!client.Any())
+ lock (ConnectedClients)
{
- continue;
+ 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);
}
- OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client.First() });
- ConnectedClients.Remove(client.First());
- removed.Add(kp.Key);
}
}
- }
- lock (LastDataRecievedTime)
- {
- foreach (var r in removed)
+ lock (LastDataReceivedTime)
{
- LastDataRecievedTime.Remove(r);
+ foreach (var r in removed)
+ {
+ LastDataReceivedTime.Remove(r);
+ }
}
- }
- };
+ };
+ }
+ Listener = 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;
+ }
+
+ break;
}
- Listener = new Socket(IPAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
- break;
- }
}
Listener.ReceiveBufferSize = ClientConnection.BufferSize;
Listener.SendBufferSize = ClientConnection.BufferSize;
@@ -201,6 +230,47 @@ namespace EonaCat.Sockets
}
}
+ ///
+ /// Setup this udp socket to override the default one
+ /// (default: null => using default)
+ ///
+ public Socket CustomUdpSocket { get; set; }
+
+ ///
+ /// Setup this tcp socket to override the default one
+ /// (default: null => using default)
+ ///
+ public Socket CustomTcpSocket { get; set; }
+
+ static void SetConnectionReset(Socket socket)
+ {
+ try
+ {
+ 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);
+ };
+ }
+ catch { }
+ }
+
+ private void ConfigureSocketOptions()
+ {
+ // Disable ICMP packet shutdown
+ SetConnectionReset(Listener);
+
+ if (ReuseAddress)
+ {
+ Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+ }
+
+ Listener.Blocking = IsSocketInBlockingMode;
+ }
+
///
/// Stop server
///
@@ -209,18 +279,18 @@ namespace EonaCat.Sockets
try
{
DisconnectTimer.Stop();
- foreach (var c in ConnectedClients)
+ foreach (var client in ConnectedClients)
{
- OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = c });
- c.Socket.Close();
+ OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
+ client.Socket.Close();
}
ConnectedClients.Clear();
OnStop?.Invoke(this, EventArgs.Empty);
Listener.Close();
}
- catch (SocketException se)
+ catch (SocketException socketException)
{
- OnError?.Invoke(this, new ErrorEventArgs(se));
+ OnError?.Invoke(this, new ErrorEventArgs(socketException));
}
}
@@ -228,7 +298,7 @@ namespace EonaCat.Sockets
{
try
{
- OnStart?.Invoke(this, EventArgs.Empty);
+ OnStart?.Invoke(this, CustomTcpSocket != null || CustomUdpSocket != null ? "Custom socket was used" : string.Empty);
if (ServerType == NetworkType.Tcp)
{
Listener.BeginAccept(AcceptCallback, Listener);
@@ -317,15 +387,7 @@ namespace EonaCat.Sockets
var buffer = objects[0] as byte[];
var remoteIp = objects[1] as EndPoint;
var listener = objects[2] as Socket;
- var bytesRead = 0;
- try
- {
- bytesRead = listener.EndReceiveFrom(ar, ref remoteIp);
- }
- catch (SocketException se)
- {
- // ignore
- }
+ var bytesRead = listener.EndReceiveFrom(ar, ref remoteIp);
var clients = ConnectedClients.Where(x => x.Guid == remoteIp.ToString()).ToList();
ClientConnection client;
if (clients.Count == 0)
@@ -355,13 +417,13 @@ namespace EonaCat.Sockets
}
else
{
- if (LastDataRecievedTime.ContainsKey(remoteIp))
+ if (LastDataReceivedTime.ContainsKey(remoteIp))
{
- LastDataRecievedTime[remoteIp] = TimeNow;
+ LastDataReceivedTime[remoteIp] = TimeNow;
}
else
{
- LastDataRecievedTime.Add(remoteIp, TimeNow);
+ LastDataReceivedTime.Add(remoteIp, TimeNow);
}
}
Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteIp, AcceptCallbackUDP, new object[] { buffer, remoteIp, Listener });