From 634ad7e14fe252ffe2bd578cb0709503c05e4766 Mon Sep 17 00:00:00 2001 From: ascet-tomsk <118526659+ascet-tomsk@users.noreply.github.com> Date: Mon, 19 Jan 2026 02:20:13 +0700 Subject: [PATCH] =?UTF-8?q?=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D1=82=D0=BE=D0=BA=D0=BE=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- f-cln/Properties/launchSettings.json | 2 +- f-srv/Program.cs | 396 ++++++++++++++++++--------- 2 files changed, 265 insertions(+), 133 deletions(-) diff --git a/f-cln/Properties/launchSettings.json b/f-cln/Properties/launchSettings.json index 52669a9..5852caa 100644 --- a/f-cln/Properties/launchSettings.json +++ b/f-cln/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "f-cln": { "commandName": "Project", - "commandLineArgs": "--port 1771 -i fe80::215:5dff:fe12:ec9" + "commandLineArgs": "--port 1771 -i fe80::215:5dff:fe12:ec9 -m 123." } } } \ No newline at end of file diff --git a/f-srv/Program.cs b/f-srv/Program.cs index 7e1691f..f67291e 100644 --- a/f-srv/Program.cs +++ b/f-srv/Program.cs @@ -6,6 +6,8 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Threading; +using System.Collections.Generic; +using System.Linq; namespace f_srv { @@ -13,6 +15,10 @@ namespace f_srv { private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private static TcpListener? _listener; + private static bool _isPaused = false; + private static readonly object _lockObject = new object(); + private static List _connectedClients = new List(); + private static bool _isRunning = false; static async Task Main(string[] args) { @@ -20,44 +26,13 @@ namespace f_srv Option ipOption = new("address", new[] { "--ip", "-i" }) { Description = "IP адрес для прослушивания (по умолчанию: все интерфейсы)", - 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); - } + DefaultValueFactory = parseResult => IPAddress.Any }; Option portOption = new("port", new[] { "--port", "-p" }) { Description = "Порт для прослушивания (по умолчанию: 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. - } - } + DefaultValueFactory = parseResult => 1771 }; var rootCommand = new RootCommand("Сервер для получения строк и отправки их в обратном порядке") @@ -78,62 +53,130 @@ namespace f_srv 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(); - if (!string.IsNullOrEmpty(input) && - input.Trim().Equals("Exit", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - return false; - }); + case "старт": + if (!_isRunning) + { + await StartServer(ip, port); + _isRunning = true; + Console.WriteLine("Сервер запущен"); + } + else + { + Console.WriteLine("Сервер уже запущен"); + } + break; - // Ожидаем либо ввод "Exit", либо завершение сервера - var completedTask = await Task.WhenAny(serverTask, exitTask); + case "стоп": + if (_isRunning) + { + await StopServer(); + _isRunning = false; + Console.WriteLine("Сервер остановлен"); + } + else + { + Console.WriteLine("Сервер уже остановлен"); + } + break; - if (completedTask == exitTask && exitTask.Result) - { - // Пользователь ввел Exit - if (!_cancellationTokenSource.IsCancellationRequested) - { - Console.WriteLine("Остановка сервера..."); - _cancellationTokenSource.Cancel(); - _listener?.Stop(); + case "пауза": + if (_isRunning && !_isPaused) + { + _isPaused = true; + Console.WriteLine("Сервер приостановлен. Новые подключения не обрабатываются."); + } + else if (!_isRunning) + { + Console.WriteLine("Сервер не запущен"); + } + else + { + Console.WriteLine("Сервер уже приостановлен"); + } + break; - // Даем серверу время на корректное завершение - try - { - await Task.WhenAny(serverTask, Task.Delay(2000)); - } - catch - { - // Игнорируем исключения при завершении - } + case "продолжить": + if (_isRunning && _isPaused) + { + _isPaused = false; + Console.WriteLine("Сервер возобновил работу"); + } + 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 { @@ -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 { - Console.WriteLine($"Запуск сервера на {ip}:{port}"); + lock (_lockObject) + { + _isPaused = false; + _connectedClients.Clear(); + } // Создание TCP listener _listener = new TcpListener(ip, port); _listener.Start(); - Console.WriteLine("Сервер запущен. Ожидание подключений..."); + Console.WriteLine($"Сервер запущен на {ip}:{port}"); + Console.WriteLine("Ожидание подключений..."); - while (!cancellationToken.IsCancellationRequested) - { - 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}"); - } - } - } + // Запускаем обработку подключений в фоновом потоке + _ = Task.Run(() => AcceptConnectionsAsync()); } catch (Exception ex) { - if (!cancellationToken.IsCancellationRequested) - { - Console.WriteLine($"Ошибка: {ex.Message}"); - } + Console.WriteLine($"Ошибка при запуске сервера: {ex.Message}"); + throw; } - finally + } + + static async Task AcceptConnectionsAsync() + { + while (!_cancellationTokenSource.Token.IsCancellationRequested) { 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; Console.WriteLine($"Подключен клиент: {clientEndPoint}"); @@ -224,7 +266,10 @@ namespace f_srv using (var reader = new StreamReader(stream, Encoding.UTF8)) 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 { @@ -238,6 +283,13 @@ namespace f_srv break; } + // Если сервер на паузе, ждем + if (_isPaused) + { + await writer.WriteLineAsync("Сервер приостановлен. Попробуйте позже."); + continue; + } + Console.WriteLine($"Получено от {clientEndPoint}: {line}"); // Реверсирование строки @@ -247,11 +299,6 @@ namespace f_srv // Отправка реверсированной строки обратно клиенту await writer.WriteLineAsync(reversedString); } - catch (OperationCanceledException) - { - // Игнорируем отмену при чтении/записи - break; - } catch (IOException ex) { // Ошибка ввода/вывода - клиент отключился @@ -261,10 +308,95 @@ namespace f_srv } } } - catch (Exception ex) when (!cancellationToken.IsCancellationRequested) + catch (Exception ex) { 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)