изменен протокол

This commit is contained in:
ascet-tomsk
2026-01-19 02:20:13 +07:00
parent 9b79d41f97
commit 634ad7e14f
2 changed files with 265 additions and 133 deletions

View File

@@ -2,7 +2,7 @@
"profiles": { "profiles": {
"f-cln": { "f-cln": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "--port 1771 -i fe80::215:5dff:fe12:ec9" "commandLineArgs": "--port 1771 -i fe80::215:5dff:fe12:ec9 -m 123."
} }
} }
} }

View File

@@ -6,6 +6,8 @@ using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Threading; using System.Threading;
using System.Collections.Generic;
using System.Linq;
namespace f_srv namespace f_srv
{ {
@@ -13,6 +15,10 @@ namespace f_srv
{ {
private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private static TcpListener? _listener; private static TcpListener? _listener;
private static bool _isPaused = false;
private static readonly object _lockObject = new object();
private static List<TcpClient> _connectedClients = new List<TcpClient>();
private static bool _isRunning = false;
static async Task<int> Main(string[] args) static async Task<int> Main(string[] args)
{ {
@@ -20,44 +26,13 @@ namespace f_srv
Option<IPAddress> ipOption = new("address", new[] { "--ip", "-i" }) Option<IPAddress> ipOption = new("address", new[] { "--ip", "-i" })
{ {
Description = "IP адрес для прослушивания (по умолчанию: все интерфейсы)", Description = "IP адрес для прослушивания (по умолчанию: все интерфейсы)",
DefaultValueFactory = parseResult => IPAddress.Any, DefaultValueFactory = parseResult => IPAddress.Any
CustomParser = result =>
{
if (result.Tokens.Count != 1)
{
result.AddError("--address requires one argument");
return IPAddress.Any;
}
return IPAddress.Parse(result.Tokens.Single().Value);
}
}; };
Option<int> portOption = new("port", new[] { "--port", "-p" }) Option<int> portOption = new("port", new[] { "--port", "-p" })
{ {
Description = "Порт для прослушивания (по умолчанию: 1771)", Description = "Порт для прослушивания (по умолчанию: 1771)",
DefaultValueFactory = parseResult => 1771, DefaultValueFactory = parseResult => 1771
CustomParser = result =>
{
if (!result.Tokens.Any())
{
return 1771;
}
if (int.TryParse(result.Tokens.Single().Value, out var delay))
{
if (delay < 1)
{
result.AddError("Must be greater than 0");
}
return delay;
}
else
{
result.AddError("Not an int.");
return 0; // Ignored.
}
}
}; };
var rootCommand = new RootCommand("Сервер для получения строк и отправки их в обратном порядке") var rootCommand = new RootCommand("Сервер для получения строк и отправки их в обратном порядке")
@@ -78,62 +53,130 @@ namespace f_srv
return 2; return 2;
} }
// Запускаем сервер в отдельной задаче // Запускаем сервер
var serverTask = Task.Run(() => StartServer(ip, port, _cancellationTokenSource.Token)); Console.WriteLine($"Запуск сервера на {ip}:{port}");
Console.WriteLine("Команды управления сервером:");
Console.WriteLine(" старт - запустить сервер");
Console.WriteLine(" стоп - остановить сервер");
Console.WriteLine(" пауза - приостановить обработку подключений");
Console.WriteLine(" продолжить - возобновить обработку подключений");
Console.WriteLine(" рестарт - перезапустить сервер");
Console.WriteLine(" статус - показать текущее состояние сервера");
Console.WriteLine(" выход - завершить программу");
Console.WriteLine();
Console.WriteLine("Сервер запущен. Введите 'Exit' для остановки..."); // Команда старт по умолчанию
await StartServer(ip, port);
_isRunning = true;
// Ждем ввод строки "Exit" в отдельном потоке // Основной цикл обработки команд
var exitTask = Task.Run(() => while (true)
{ {
while (!_cancellationTokenSource.IsCancellationRequested) Console.Write("сервер> ");
var command = Console.ReadLine()?.Trim().ToLower();
if (string.IsNullOrEmpty(command))
continue;
switch (command)
{ {
var input = Console.ReadLine(); case "старт":
if (!string.IsNullOrEmpty(input) && if (!_isRunning)
input.Trim().Equals("Exit", StringComparison.OrdinalIgnoreCase)) {
{ await StartServer(ip, port);
return true; _isRunning = true;
} Console.WriteLine("Сервер запущен");
} }
return false; else
}); {
Console.WriteLine("Сервер уже запущен");
}
break;
// Ожидаем либо ввод "Exit", либо завершение сервера case "стоп":
var completedTask = await Task.WhenAny(serverTask, exitTask); if (_isRunning)
{
await StopServer();
_isRunning = false;
Console.WriteLine("Сервер остановлен");
}
else
{
Console.WriteLine("Сервер уже остановлен");
}
break;
if (completedTask == exitTask && exitTask.Result) case "пауза":
{ if (_isRunning && !_isPaused)
// Пользователь ввел Exit {
if (!_cancellationTokenSource.IsCancellationRequested) _isPaused = true;
{ Console.WriteLine("Сервер приостановлен. Новые подключения не обрабатываются.");
Console.WriteLine("Остановка сервера..."); }
_cancellationTokenSource.Cancel(); else if (!_isRunning)
_listener?.Stop(); {
Console.WriteLine("Сервер не запущен");
}
else
{
Console.WriteLine("Сервер уже приостановлен");
}
break;
// Даем серверу время на корректное завершение case "продолжить":
try if (_isRunning && _isPaused)
{ {
await Task.WhenAny(serverTask, Task.Delay(2000)); _isPaused = false;
} Console.WriteLine("Сервер возобновил работу");
catch }
{ else if (!_isRunning)
// Игнорируем исключения при завершении {
} Console.WriteLine("Сервер не запущен");
}
else
{
Console.WriteLine("Сервер уже работает");
}
break;
Console.WriteLine("Сервер остановлен."); case "рестарт":
if (_isRunning)
{
await StopServer();
Console.WriteLine("Сервер остановлен");
}
await Task.Delay(1000); // Небольшая задержка перед перезапуском
await StartServer(ip, port);
_isRunning = true;
_isPaused = false;
Console.WriteLine("Сервер перезапущен");
break;
case "статус":
PrintServerStatus();
break;
case "выход":
case "exit":
Console.WriteLine("Завершение работы сервера...");
if (_isRunning)
{
await StopServer();
}
_cancellationTokenSource.Cancel();
return 0;
case "помощь":
case "help":
PrintHelp();
break;
default:
Console.WriteLine($"Неизвестная команда: {command}");
Console.WriteLine("Введите 'помощь' для списка команд");
break;
} }
} }
else
{
// Сервер завершился сам (ошибка или другая причина)
if (!_cancellationTokenSource.IsCancellationRequested)
{
_cancellationTokenSource.Cancel();
}
Console.WriteLine("Сервер завершил работу.");
}
return 0;
} }
else else
{ {
@@ -145,74 +188,73 @@ namespace f_srv
} }
} }
static async Task StartServer(IPAddress ip, int port, CancellationToken cancellationToken) static async Task StartServer(IPAddress ip, int port)
{ {
try try
{ {
Console.WriteLine($"Запуск сервера на {ip}:{port}"); lock (_lockObject)
{
_isPaused = false;
_connectedClients.Clear();
}
// Создание TCP listener // Создание TCP listener
_listener = new TcpListener(ip, port); _listener = new TcpListener(ip, port);
_listener.Start(); _listener.Start();
Console.WriteLine("Сервер запущен. Ожидание подключений..."); Console.WriteLine($"Сервер запущен на {ip}:{port}");
Console.WriteLine("Ожидание подключений...");
while (!cancellationToken.IsCancellationRequested) // Запускаем обработку подключений в фоновом потоке
{ _ = Task.Run(() => AcceptConnectionsAsync());
try
{
// Ожидание подключения клиента с таймаутом для проверки отмены
var acceptTask = _listener.AcceptTcpClientAsync();
var completedTask = await Task.WhenAny(acceptTask, Task.Delay(1000, cancellationToken));
if (completedTask == acceptTask && !cancellationToken.IsCancellationRequested)
{
var client = await acceptTask;
// Обработка клиента в отдельной задаче
_ = Task.Run(async () => await HandleClient(client, cancellationToken));
}
}
catch (OperationCanceledException)
{
// Игнорируем отмену
break;
}
catch (ObjectDisposedException)
{
// Listener был остановлен
break;
}
catch (Exception ex)
{
if (!cancellationToken.IsCancellationRequested)
{
Console.WriteLine($"Ошибка при принятии подключения: {ex.Message}");
}
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
if (!cancellationToken.IsCancellationRequested) Console.WriteLine($"Ошибка при запуске сервера: {ex.Message}");
{ throw;
Console.WriteLine($"Ошибка: {ex.Message}");
}
} }
finally }
static async Task AcceptConnectionsAsync()
{
while (!_cancellationTokenSource.Token.IsCancellationRequested)
{ {
try try
{ {
_listener?.Stop(); // Если сервер на паузе, ждем
if (_isPaused)
{
await Task.Delay(1000);
continue;
}
// Ожидание подключения клиента
var client = await _listener!.AcceptTcpClientAsync();
lock (_lockObject)
{
_connectedClients.Add(client);
}
// Обработка клиента в отдельной задаче
_ = Task.Run(async () => await HandleClient(client));
} }
catch catch (ObjectDisposedException)
{ {
// Игнорируем ошибки при остановке // Listener был остановлен
break;
}
catch (Exception ex)
{
if (!_cancellationTokenSource.Token.IsCancellationRequested)
{
Console.WriteLine($"Ошибка при принятии подключения: {ex.Message}");
}
} }
} }
} }
static async Task HandleClient(TcpClient client, CancellationToken cancellationToken) static async Task HandleClient(TcpClient client)
{ {
var clientEndPoint = client.Client.RemoteEndPoint; var clientEndPoint = client.Client.RemoteEndPoint;
Console.WriteLine($"Подключен клиент: {clientEndPoint}"); Console.WriteLine($"Подключен клиент: {clientEndPoint}");
@@ -224,7 +266,10 @@ namespace f_srv
using (var reader = new StreamReader(stream, Encoding.UTF8)) using (var reader = new StreamReader(stream, Encoding.UTF8))
using (var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true }) using (var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true })
{ {
while (!cancellationToken.IsCancellationRequested) // Отправка приветственного сообщения
await writer.WriteLineAsync($"hello {clientEndPoint}");
while (client.Connected && !_cancellationTokenSource.Token.IsCancellationRequested)
{ {
try try
{ {
@@ -238,6 +283,13 @@ namespace f_srv
break; break;
} }
// Если сервер на паузе, ждем
if (_isPaused)
{
await writer.WriteLineAsync("Сервер приостановлен. Попробуйте позже.");
continue;
}
Console.WriteLine($"Получено от {clientEndPoint}: {line}"); Console.WriteLine($"Получено от {clientEndPoint}: {line}");
// Реверсирование строки // Реверсирование строки
@@ -247,11 +299,6 @@ namespace f_srv
// Отправка реверсированной строки обратно клиенту // Отправка реверсированной строки обратно клиенту
await writer.WriteLineAsync(reversedString); await writer.WriteLineAsync(reversedString);
} }
catch (OperationCanceledException)
{
// Игнорируем отмену при чтении/записи
break;
}
catch (IOException ex) catch (IOException ex)
{ {
// Ошибка ввода/вывода - клиент отключился // Ошибка ввода/вывода - клиент отключился
@@ -261,10 +308,95 @@ namespace f_srv
} }
} }
} }
catch (Exception ex) when (!cancellationToken.IsCancellationRequested) catch (Exception ex)
{ {
Console.WriteLine($"Ошибка при работе с клиентом {clientEndPoint}: {ex.Message}"); Console.WriteLine($"Ошибка при работе с клиентом {clientEndPoint}: {ex.Message}");
} }
finally
{
lock (_lockObject)
{
_connectedClients.Remove(client);
}
Console.WriteLine($"Клиент отключен: {clientEndPoint}");
}
}
static async Task StopServer()
{
try
{
// Останавливаем listener
_listener?.Stop();
// Закрываем все подключенные клиенты
lock (_lockObject)
{
foreach (var client in _connectedClients.ToList())
{
try
{
client.Close();
}
catch
{
// Игнорируем ошибки при закрытии клиентов
}
}
_connectedClients.Clear();
}
_isPaused = false;
Console.WriteLine("Сервер остановлен");
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка при остановке сервера: {ex.Message}");
}
}
static void PrintServerStatus()
{
Console.WriteLine("\n=== Статус сервера ===");
Console.WriteLine($"Состояние: {(_isRunning ? "Запущен" : "Остановлен")}");
if (_isRunning)
{
Console.WriteLine($"Режим: {(_isPaused ? "Приостановлен" : "Работает")}");
lock (_lockObject)
{
Console.WriteLine($"Подключенных клиентов: {_connectedClients.Count}");
foreach (var client in _connectedClients)
{
try
{
if (client.Client.RemoteEndPoint is IPEndPoint endPoint)
{
Console.WriteLine($" {endPoint.Address}:{endPoint.Port}");
}
}
catch
{
// Игнорируем клиентов с ошибками
}
}
}
}
Console.WriteLine("====================\n");
}
static void PrintHelp()
{
Console.WriteLine("\n=== Команды управления сервером ===");
Console.WriteLine(" старт - запустить сервер");
Console.WriteLine(" стоп - остановить сервер");
Console.WriteLine(" пауза - приостановить обработку подключений");
Console.WriteLine(" продолжить - возобновить обработку подключений");
Console.WriteLine(" рестарт - перезапустить сервер");
Console.WriteLine(" статус - показать текущее состояние сервера");
Console.WriteLine(" помощь - показать эту справку");
Console.WriteLine(" выход - завершить программу");
Console.WriteLine("===================================\n");
} }
static string ReverseString(string s) static string ReverseString(string s)