diff --git a/MTSC-TestServer/Program.cs b/MTSC-TestServer/Program.cs
index 63c0be1..10f7dbe 100644
--- a/MTSC-TestServer/Program.cs
+++ b/MTSC-TestServer/Program.cs
@@ -4,6 +4,7 @@ using MTSC.Exceptions;
using MTSC.Logging;
using MTSC.Server;
using MTSC.Server.Handlers;
+using MTSC.Server.UsageMonitors;
using System;
using System.Numerics;
using System.Security.Cryptography;
@@ -17,14 +18,13 @@ namespace MTSC_TestServer
{
X509Certificate2 certificate = new X509Certificate2("localhost.pfx", "psdsd");
Server server = new Server(80);
- server.TickRate = 60;
- server.ScaleUsage = true;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(1024);
EncryptionHandler encryptionHandler = new EncryptionHandler(rsa);
server
//.AddHandler(encryptionHandler)
.AddLogger(new ConsoleLogger())
.AddLogger(new DebugConsoleLogger())
+ .AddServerUsageMonitor(new TickrateEnforcer().SetTicksPerSecond(60))
.AddExceptionHandler(new ExceptionConsoleLogger())
//.AddHandler(new BroadcastHandler())
.AddHandler(new WebsocketHandler().AddWebsocketHandler(new BroadcastModule()))
diff --git a/MTSC/MTSC.csproj b/MTSC/MTSC.csproj
index 502e34b..a7ad732 100644
--- a/MTSC/MTSC.csproj
+++ b/MTSC/MTSC.csproj
@@ -5,12 +5,12 @@
netcoreapp2.1;net48;netstandard2.0;netcoreapp3.0
- 1.0.7
+ 1.1.0
Alexandru-Victor Macocian
MTSC
Modular TCP Server and Client
- 0.1.0.7
- 0.1.0.7
+ 0.1.1.0
+ 0.1.1.0
true
AnyCPU;x64
https://github.com/AlexMacocian/MTSC
diff --git a/MTSC/Server/Server.cs b/MTSC/Server/Server.cs
index 025d9c3..43cef12 100644
--- a/MTSC/Server/Server.cs
+++ b/MTSC/Server/Server.cs
@@ -1,6 +1,7 @@
using MTSC.Exceptions;
using MTSC.Logging;
using MTSC.Server.Handlers;
+using MTSC.Server.UsageMonitors;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -23,14 +24,14 @@ namespace MTSC.Server
bool running;
X509Certificate2 certificate;
TcpListener listener;
- int port = 50;
+ int port = 80;
List toRemove = new List();
List clients = new List();
List handlers = new List();
List loggers = new List();
List exceptionHandlers = new List();
+ List serverUsageMonitors = new List();
ConcurrentQueue> messageQueue = new ConcurrentQueue>();
- int loopMillis = 16;
#endregion
#region Properties
///
@@ -45,21 +46,6 @@ namespace MTSC.Server
/// List of clients currently connected to the server.
///
public List Clients { get => clients; set => clients = value; }
- ///
- /// If set to true, the server will use an algorithm to lower or increase the CPU usage
- /// based on demands.
- ///
- public bool ScaleUsage { get; set; }
- ///
- /// How many times does the server proc per second. Cannot be set higher than 1000.
- /// This tickrate will be respected if either the ForceTickrate is set to true or
- /// ScaleUsage is set to true and the server is in power saving mode.
- ///
- public int TickRate { get => 1000 / loopMillis; set => loopMillis = 1000 / Math.Min(value, 1000); }
- ///
- /// If set to true, the server will respect the provided TickRate, regardless of current server load.
- ///
- public bool ForceTickrate { get; set; }
#endregion
#region Constructors
///
@@ -100,7 +86,7 @@ namespace MTSC.Server
return this;
}
///
- /// Adds a handler to the server.
+ /// Adds a to the server.
///
/// Handler to be added.
/// This server object.
@@ -110,7 +96,7 @@ namespace MTSC.Server
return this;
}
///
- /// Adds a logger to the server.
+ /// Adds a to the server.
///
/// Logger to be added.
/// This server object.
@@ -120,7 +106,7 @@ namespace MTSC.Server
return this;
}
///
- /// Adds an exception handler to the server.
+ /// Adds an to the server.
///
/// Handler to be added.
/// This server object.
@@ -130,6 +116,16 @@ namespace MTSC.Server
return this;
}
///
+ /// Adds a to the server.
+ ///
+ /// Monitor to be added.
+ /// This server object.
+ public Server AddServerUsageMonitor(IServerUsageMonitor serverUsageMonitor)
+ {
+ serverUsageMonitors.Add(serverUsageMonitor);
+ return this;
+ }
+ ///
/// Queues a message to be sent.
///
/// Target client.
@@ -141,7 +137,7 @@ namespace MTSC.Server
///
/// Adds a message to be logged by the associated loggers.
///
- /// Message to be logged
+ /// Message to be logged
public void Log(string log)
{
foreach (ILogger logger in loggers)
@@ -152,7 +148,7 @@ namespace MTSC.Server
///
/// Adds a debug message to be logged by the associated loggers.
///
- /// Debug message to be logged
+ /// Debug message to be logged
public void LogDebug(string debugMessage)
{
foreach (ILogger logger in loggers)
@@ -366,13 +362,11 @@ namespace MTSC.Server
}
}
/*
- * If the server load is low or the server has a forced tickrate,
- * sleep an amount of milliseconds to lower the CPU usage.
+ * Call the usage monitors and let them scale or determine current resource usage.
*/
- if(((DateTime.Now - lastLoad).TotalMilliseconds > 1000) && ScaleUsage ||
- ForceTickrate)
+ foreach(IServerUsageMonitor usageMonitor in serverUsageMonitors)
{
- Thread.Sleep((int)Math.Max(loopMillis - (DateTime.Now - startLoopTime).TotalMilliseconds, 0));
+ usageMonitor.Tick(this);
}
}
}
diff --git a/MTSC/Server/UsageMonitors/CPUUsageLimiter.cs b/MTSC/Server/UsageMonitors/CPUUsageLimiter.cs
new file mode 100644
index 0000000..631378d
--- /dev/null
+++ b/MTSC/Server/UsageMonitors/CPUUsageLimiter.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MTSC.Server.UsageMonitors
+{
+ ///
+ /// Implementation of that limits CPU usage to a given value.
+ ///
+ public class CPUUsageLimiter : IServerUsageMonitor
+ {
+ private double cpuUsage;
+ private volatile bool polling = false;
+ private int cpuUsageLimit = 60;
+
+ ///
+ /// Set the CPU usage limit. Bounded between 0 and 100%.
+ ///
+ public int CPUUsageLimit { get => cpuUsageLimit;
+ set
+ {
+ cpuUsageLimit = Math.Max(Math.Min(value, 100), 0);
+ }
+ }
+ ///
+ /// Sets the value.
+ ///
+ /// Value to be set.
+ /// This
+ public CPUUsageLimiter SetCPUUsageLimit(int cpuUsageLimit)
+ {
+ CPUUsageLimit = cpuUsageLimit;
+ return this;
+ }
+
+ void IServerUsageMonitor.Tick(Server server)
+ {
+ PollCPUUsage();
+ while(cpuUsage > cpuUsageLimit)
+ {
+ Thread.Sleep(10);
+ }
+ }
+
+ private async void PollCPUUsage()
+ {
+ if (!polling)
+ {
+ polling = true;
+ var startTime = DateTime.UtcNow;
+ var startCpuUsage = Process.GetCurrentProcess().TotalProcessorTime;
+ await Task.Delay(500);
+
+ var endTime = DateTime.UtcNow;
+ var endCpuUsage = Process.GetCurrentProcess().TotalProcessorTime;
+ var cpuUsedMs = (endCpuUsage - startCpuUsage).TotalMilliseconds;
+ var totalMsPassed = (endTime - startTime).TotalMilliseconds;
+ var cpuUsageTotal = cpuUsedMs / (Environment.ProcessorCount * totalMsPassed);
+ cpuUsage = cpuUsageTotal * 100;
+ polling = false;
+ }
+ }
+ }
+}
diff --git a/MTSC/Server/UsageMonitors/IServerUsageMonitor.cs b/MTSC/Server/UsageMonitors/IServerUsageMonitor.cs
new file mode 100644
index 0000000..c859542
--- /dev/null
+++ b/MTSC/Server/UsageMonitors/IServerUsageMonitor.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MTSC.Server.UsageMonitors
+{
+ ///
+ /// Interface for server usage monitors.
+ ///
+ public interface IServerUsageMonitor
+ {
+ ///
+ /// Called each server tick.
+ /// This method determines the usage of the server as well as behaviour.
+ ///
+ ///
+ /// This is useful in case the server needs a forced tickrate or should lower CPU usage when not under heavy load.
+ /// Sleeping the current thread in this method will sleep the server thread.
+ ///
+ ///
+ void Tick(Server server);
+ }
+}
diff --git a/MTSC/Server/UsageMonitors/TickrateEnforcer.cs b/MTSC/Server/UsageMonitors/TickrateEnforcer.cs
new file mode 100644
index 0000000..bc7a929
--- /dev/null
+++ b/MTSC/Server/UsageMonitors/TickrateEnforcer.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+
+namespace MTSC.Server.UsageMonitors
+{
+ ///
+ /// Implementation of that enforces a specified tickrate.
+ ///
+ public class TickrateEnforcer : IServerUsageMonitor
+ {
+ private DateTime lastTickTime = DateTime.Now;
+
+ ///
+ /// Number of server ticks in one second.
+ ///
+ public int TicksPerSecond { get; set; }
+ ///
+ /// Sets the value.
+ ///
+ /// Value to be set.
+ /// This
+ public TickrateEnforcer SetTicksPerSecond(int ticksPerSecond)
+ {
+ TicksPerSecond = ticksPerSecond;
+ return this;
+ }
+
+ void IServerUsageMonitor.Tick(Server server)
+ {
+ if((DateTime.Now - lastTickTime).TotalMilliseconds < 1000f / TicksPerSecond)
+ {
+ Thread.Sleep((int)(1000f / TicksPerSecond - (DateTime.Now - lastTickTime).TotalMilliseconds));
+ }
+ }
+ }
+}