This commit is contained in:
Пытков Роман
2025-09-17 00:44:21 +03:00
parent 1f0e7c285c
commit bbe5a75dba
15 changed files with 783 additions and 0 deletions

88
Server/DataGenerator.cs Normal file
View File

@@ -0,0 +1,88 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Domain;
namespace Server;
public class DataGenerator
{
private static readonly Random _random = new Random();
private readonly int _minNewPackages;
private readonly int _maxPreviousPackages;
private readonly TimeSpan _generationInterval;
private readonly LinkedList<Data> _cache = new LinkedList<Data>();
private readonly ConcurrentDictionary<long, Data> _dict = [];
private readonly object _lock = new object();
private long _maxRequestedIndex = 0;
private Task _generationTask;
private CancellationTokenSource _cts = new();
public DataGenerator(int minNewPackages = 50, int maxPreviousPackages = 50, TimeSpan? generationInterval = null)
{
_minNewPackages = Math.Max(minNewPackages, 5);
_maxPreviousPackages = Math.Max(maxPreviousPackages, 5);
_generationInterval = generationInterval ?? TimeSpan.FromSeconds(1);
_generationTask = Task.Run(() => GenerateInBackground(_cts.Token));
}
private void GenerateInBackground(CancellationToken token)
{
var firstData = GenerateRandomData(0);
_cache.AddLast(firstData);
_dict[firstData.PackageIndex] = firstData;
while (!token.IsCancellationRequested)
{
//await Task.Delay(_generationInterval, token);
var first = _cache.First!.Value;
var last = _cache.Last!.Value;
if (last.PackageIndex - _maxRequestedIndex < _minNewPackages)
{
var data = GenerateRandomData(last.PackageIndex + 1);
_cache.AddLast(data);
_dict[data.PackageIndex] = data;
}
if (_maxRequestedIndex - first.PackageIndex > _maxPreviousPackages)
{
_cache.RemoveFirst();
_dict.TryRemove(first.PackageIndex, out _);
}
//System.Console.WriteLine($"[{first.PackageIndex}; {last.PackageIndex}]");
}
}
public Data? GetPackage(long packageIndex)
{
var res = _dict.TryGetValue(packageIndex, out var value);
_maxRequestedIndex = Math.Max(_maxRequestedIndex, packageIndex);
return res ? value : null;
}
private Data GenerateRandomData(long packageNumber)
{
var alpha = _random.NextDouble();
var beta = _random.NextDouble() * (1 - alpha);
var theta = 1 - alpha - beta;
var signalQuality = _random.NextDouble();
return new Data(
ConcentrationIndex: _random.NextDouble(),
RelaxationIndex: _random.NextDouble(),
CognitiveControl: _random.NextDouble(),
CognitiveLoad: _random.NextDouble(),
Alpha: alpha,
Beta: beta,
Theta: theta,
Smr: _random.NextDouble(),
MuWave: _random.NextDouble(),
Artifact: signalQuality < 0.5,
SignalQuality: signalQuality,
PackageIndex: packageNumber,
TimeOfDataGenerate: DateTime.Now
);
}
}

105
Server/HttpServer.cs Normal file
View File

@@ -0,0 +1,105 @@
using System;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Domain;
using Domain.Dto;
namespace NetworkTest;
public class HttpServer : IServer
{
private readonly HttpListener _listener;
private readonly string _url;
private CancellationTokenSource _cts = new CancellationTokenSource();
private Func<long, Data?> _getData;
private Action<Data, HttpListenerResponse> _writeResponse;
public HttpServer(Func<long, Data?> getData, Action<Data, HttpListenerResponse> writeResponse, string url = "http://*:5555/")
{
_getData = getData;
_writeResponse = writeResponse;
_url = url;
_listener = new HttpListener();
_listener.Prefixes.Add(_url);
}
public void Start()
{
_cts = new CancellationTokenSource();
_listener.Start();
Task.Run(() => ListenAsync(_cts.Token));
}
public void Stop()
{
_cts.Cancel();
_listener.Stop();
}
private async Task ListenAsync(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
try
{
var context = await _listener.GetContextAsync();
_ = Task.Run(() => HandleRequest(context));
}
catch (HttpListenerException)
{
break;
}
catch (ObjectDisposedException)
{
break;
}
}
}
private void HandleRequest(HttpListenerContext context)
{
if (context.Request.Url?.AbsolutePath.Equals("/fetchpackage", StringComparison.OrdinalIgnoreCase) == true)
{
string? indexStr = context.Request.QueryString["index"];
if (indexStr != null && long.TryParse(indexStr, out long index))
{
var data = _getData(index);
if (data != null)
{
_writeResponse(data, context.Response);
}
else
{
var responseText = JsonSerializer.Serialize(new { error = "Data not found" });
context.Response.StatusCode = 404;
byte[] buffer = Encoding.UTF8.GetBytes(responseText);
context.Response.ContentType = "application/json";
context.Response.ContentLength64 = buffer.Length;
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
}
}
else
{
context.Response.StatusCode = 400;
byte[] buffer = Encoding.UTF8.GetBytes("Invalid or missing 'index' parameter.");
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
}
}
else
{
context.Response.StatusCode = 404;
byte[] buffer = Encoding.UTF8.GetBytes("Not Found");
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
}
context.Response.OutputStream.Close();
}
public override string ToString()
{
return $"HTTP: [{string.Join(", ", _listener.Prefixes)}]";
}
}

8
Server/IServer.cs Normal file
View File

@@ -0,0 +1,8 @@
namespace NetworkTest;
interface IServer
{
public void Start();
public void Stop();
}

111
Server/Program.cs Normal file
View File

@@ -0,0 +1,111 @@
using System.Diagnostics;
using System.Net;
using System.Text;
using System.Text.Json;
using Domain;
using Domain.Dto;
using MessagePack;
using NetworkTest;
using Server;
if (args.Length < 2)
{
System.Console.WriteLine("Pass twp arg: test/http/tcp and json/bin");
return -1;
}
var dataGenerator = new DataGenerator(generationInterval: TimeSpan.FromMilliseconds(1));
var protocol = args[0];
var serialization = args[1];
if (protocol == "test")
{
int nullCount = 0;
long index = 0;
var sw = Stopwatch.StartNew();
var lastMs = 0L;
var lastIndex = 0L;
var ms = 1000;
var json = serialization == "json";
while (true)
{
var data = dataGenerator.GetPackage(index);
if (data == null)
{
nullCount++;
continue;
}
if (json)
{
JsonData jsonData = new JsonData(data);
var responseText = JsonSerializer.Serialize(jsonData);
byte[] buffer = Encoding.UTF8.GetBytes(responseText);
}
else
{
MessagePackData msgPackData = new MessagePackData(data);
byte[] buffer = MessagePackSerializer.Serialize(msgPackData);
}
index++;
var diff = sw.ElapsedMilliseconds - lastMs;
if (diff >= ms)
{
var serializrd = index - lastIndex;
System.Console.WriteLine($"Serialized {serializrd} data packages in {diff} ms.");
lastIndex = index;
lastMs = sw.ElapsedMilliseconds;
}
}
}
IServer? server = protocol == "http" ?
new HttpServer(index => dataGenerator.GetPackage(index),
serialization == "json" ? PrepareResponseJson : PrepareResponseMessagePack) :
null;
server?.Start();
System.Console.WriteLine("Server started:");
System.Console.WriteLine(server);
// Обработка выхода по Ctrl+C
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true; // Prevent immediate termination
Console.WriteLine("Shutdown signal received. Stopping server...");
server?.Stop();
Console.WriteLine("Goodbye!");
Environment.Exit(0);
};
// Бесконечный цикл ожидания
while (true)
{
Thread.Sleep(1000);
}
void PrepareResponseJson(Data data, HttpListenerResponse response)
{
JsonData jsonData = new JsonData(data);
var responseText = JsonSerializer.Serialize(jsonData);
byte[] buffer = Encoding.UTF8.GetBytes(responseText);
response.ContentType = "application/json";
response.ContentLength64 = buffer.Length;
response.OutputStream.Write(buffer, 0, buffer.Length);
}
void PrepareResponseMessagePack(Data data, HttpListenerResponse response)
{
MessagePackData msgPackData = new MessagePackData(data);
byte[] buffer = MessagePackSerializer.Serialize(msgPackData);
response.ContentType = "application/x-msgpack";
response.ContentLength64 = buffer.Length;
response.OutputStream.Write(buffer, 0, buffer.Length);
}

18
Server/Server.csproj Normal file
View File

@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Domain/Domain.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MessagePack" Version="3.1.4" />
</ItemGroup>
</Project>