Updated
This commit is contained in:
parent
6c6831396e
commit
a5e2cbaf57
|
@ -18,9 +18,9 @@
|
||||||
<PackageTags>EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server</PackageTags>
|
<PackageTags>EonaCat, Network, .NET Standard, EonaCatHelpers, Jeroen, Saey, Protocol, Quic, UDP, TCP, Web, Server</PackageTags>
|
||||||
<PackageReleaseNotes></PackageReleaseNotes>
|
<PackageReleaseNotes></PackageReleaseNotes>
|
||||||
<Description>EonaCat Networking library with Quic, TCP, UDP and a Webserver</Description>
|
<Description>EonaCat Networking library with Quic, TCP, UDP and a Webserver</Description>
|
||||||
<Version>1.0.1</Version>
|
<Version>1.0.2</Version>
|
||||||
<AssemblyVersion>1.0.0.1</AssemblyVersion>
|
<AssemblyVersion>1.0.0.2</AssemblyVersion>
|
||||||
<FileVersion>1.0.0.1</FileVersion>
|
<FileVersion>1.0.0.2</FileVersion>
|
||||||
<PackageIcon>icon.png</PackageIcon>
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,11 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace EonaCat.Sockets
|
namespace EonaCat.Sockets
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
///
|
|
||||||
/// </summary>
|
|
||||||
public class SocketServer : IDisposable
|
public class SocketServer : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -38,6 +36,19 @@ namespace EonaCat.Sockets
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int DisconnectionCheckInterval { get; set; } = 100;
|
public int DisconnectionCheckInterval { get; set; } = 100;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if we need to reuse the socket address
|
||||||
|
/// (default: false)
|
||||||
|
/// </summary>
|
||||||
|
public bool ReuseAddress { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if the socket is in blocking mode
|
||||||
|
/// (default: true)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSocketInBlockingMode { get; set; } = true;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Socket backlog. The maximum length of the pending connections queue.
|
/// Socket backlog. The maximum length of the pending connections queue.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -48,12 +59,14 @@ namespace EonaCat.Sockets
|
||||||
public NetworkType ServerType { get; set; }
|
public NetworkType ServerType { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Only for UDP. Require to use SocketClient class for this.
|
/// Only for UDP.
|
||||||
|
/// Required to use SocketClient class for this.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UDPClientManage { get; set; } = true;
|
public bool UDPClientManage { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Only for UDP. Accept 1 byte data for check connected state.
|
/// Only for UDP.
|
||||||
|
/// Accept 1 byte data for connected state check.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int _UDPDataInterval { get => (int)(UDPDataInterval * 1.5); }
|
private int _UDPDataInterval { get => (int)(UDPDataInterval * 1.5); }
|
||||||
public int UDPDataInterval { get; set; } = 5000;
|
public int UDPDataInterval { get; set; } = 5000;
|
||||||
|
@ -77,7 +90,7 @@ namespace EonaCat.Sockets
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when executing Start() function
|
/// Called when executing Start() function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler OnStart;
|
public event EventHandler<string> OnStart;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when executing Stop() function
|
/// Called when executing Stop() function
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -85,7 +98,7 @@ namespace EonaCat.Sockets
|
||||||
|
|
||||||
private Socket Listener { get; set; }
|
private Socket Listener { get; set; }
|
||||||
private System.Timers.Timer DisconnectTimer { get; set; }
|
private System.Timers.Timer DisconnectTimer { get; set; }
|
||||||
private Dictionary<EndPoint, double> LastDataRecievedTime { get; set; }
|
private Dictionary<EndPoint, double> LastDataReceivedTime { get; set; }
|
||||||
private double TimeNow { get => (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
|
private double TimeNow { get => (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
|
||||||
|
|
||||||
public SocketServer(NetworkType type, string address, int port)
|
public SocketServer(NetworkType type, string address, int port)
|
||||||
|
@ -128,6 +141,14 @@ namespace EonaCat.Sockets
|
||||||
{
|
{
|
||||||
case NetworkType.Tcp:
|
case NetworkType.Tcp:
|
||||||
Listener = new Socket(IPAddress.AddressFamily, SocketType.Stream, ProtocolType.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) =>
|
DisconnectTimer.Elapsed += (s, e) =>
|
||||||
{
|
{
|
||||||
lock (ConnectedClients)
|
lock (ConnectedClients)
|
||||||
|
@ -149,11 +170,11 @@ namespace EonaCat.Sockets
|
||||||
{
|
{
|
||||||
if (UDPClientManage)
|
if (UDPClientManage)
|
||||||
{
|
{
|
||||||
LastDataRecievedTime = new Dictionary<EndPoint, double>();
|
LastDataReceivedTime = new Dictionary<EndPoint, double>();
|
||||||
DisconnectTimer.Elapsed += (s, e) =>
|
DisconnectTimer.Elapsed += (s, e) =>
|
||||||
{
|
{
|
||||||
var now = TimeNow;
|
var now = TimeNow;
|
||||||
var times = LastDataRecievedTime;
|
var times = LastDataReceivedTime;
|
||||||
var removed = new List<EndPoint>();
|
var removed = new List<EndPoint>();
|
||||||
foreach (var kp in times)
|
foreach (var kp in times)
|
||||||
{
|
{
|
||||||
|
@ -172,16 +193,24 @@ namespace EonaCat.Sockets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lock (LastDataRecievedTime)
|
lock (LastDataReceivedTime)
|
||||||
{
|
{
|
||||||
foreach (var r in removed)
|
foreach (var r in removed)
|
||||||
{
|
{
|
||||||
LastDataRecievedTime.Remove(r);
|
LastDataReceivedTime.Remove(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Listener = new Socket(IPAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,6 +230,47 @@ namespace EonaCat.Sockets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setup this udp socket to override the default one
|
||||||
|
/// (default: null => using default)
|
||||||
|
/// </summary>
|
||||||
|
public Socket CustomUdpSocket { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Setup this tcp socket to override the default one
|
||||||
|
/// (default: null => using default)
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stop server
|
/// Stop server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -209,18 +279,18 @@ namespace EonaCat.Sockets
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
DisconnectTimer.Stop();
|
DisconnectTimer.Stop();
|
||||||
foreach (var c in ConnectedClients)
|
foreach (var client in ConnectedClients)
|
||||||
{
|
{
|
||||||
OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = c });
|
OnDisconnected?.Invoke(this, new SocketServerClientEventArgs() { Client = client });
|
||||||
c.Socket.Close();
|
client.Socket.Close();
|
||||||
}
|
}
|
||||||
ConnectedClients.Clear();
|
ConnectedClients.Clear();
|
||||||
OnStop?.Invoke(this, EventArgs.Empty);
|
OnStop?.Invoke(this, EventArgs.Empty);
|
||||||
Listener.Close();
|
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
|
try
|
||||||
{
|
{
|
||||||
OnStart?.Invoke(this, EventArgs.Empty);
|
OnStart?.Invoke(this, CustomTcpSocket != null || CustomUdpSocket != null ? "Custom socket was used" : string.Empty);
|
||||||
if (ServerType == NetworkType.Tcp)
|
if (ServerType == NetworkType.Tcp)
|
||||||
{
|
{
|
||||||
Listener.BeginAccept(AcceptCallback, Listener);
|
Listener.BeginAccept(AcceptCallback, Listener);
|
||||||
|
@ -317,15 +387,7 @@ namespace EonaCat.Sockets
|
||||||
var buffer = objects[0] as byte[];
|
var buffer = objects[0] as byte[];
|
||||||
var remoteIp = objects[1] as EndPoint;
|
var remoteIp = objects[1] as EndPoint;
|
||||||
var listener = objects[2] as Socket;
|
var listener = objects[2] as Socket;
|
||||||
var bytesRead = 0;
|
var bytesRead = listener.EndReceiveFrom(ar, ref remoteIp);
|
||||||
try
|
|
||||||
{
|
|
||||||
bytesRead = listener.EndReceiveFrom(ar, ref remoteIp);
|
|
||||||
}
|
|
||||||
catch (SocketException se)
|
|
||||||
{
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
var clients = ConnectedClients.Where(x => x.Guid == remoteIp.ToString()).ToList();
|
var clients = ConnectedClients.Where(x => x.Guid == remoteIp.ToString()).ToList();
|
||||||
ClientConnection client;
|
ClientConnection client;
|
||||||
if (clients.Count == 0)
|
if (clients.Count == 0)
|
||||||
|
@ -355,13 +417,13 @@ namespace EonaCat.Sockets
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (LastDataRecievedTime.ContainsKey(remoteIp))
|
if (LastDataReceivedTime.ContainsKey(remoteIp))
|
||||||
{
|
{
|
||||||
LastDataRecievedTime[remoteIp] = TimeNow;
|
LastDataReceivedTime[remoteIp] = TimeNow;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LastDataRecievedTime.Add(remoteIp, TimeNow);
|
LastDataReceivedTime.Add(remoteIp, TimeNow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteIp, AcceptCallbackUDP, new object[] { buffer, remoteIp, Listener });
|
Listener.BeginReceiveFrom(buffer, 0, ClientConnection.BufferSize, 0, ref remoteIp, AcceptCallbackUDP, new object[] { buffer, remoteIp, Listener });
|
||||||
|
|
Loading…
Reference in New Issue