using System; using System.CommandLine; using System.CommandLine.Parsing; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Threading; namespace f_srv { class Program { private static CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private static TcpListener? _listener; static async Task Main(string[] args) { // Создание команды с аргументами 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); } }; 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. } } }; var rootCommand = new RootCommand("Сервер для получения строк и отправки их в обратном порядке") { ipOption, portOption }; ParseResult parseResult = rootCommand.Parse(args); if (parseResult.Errors.Count == 0) { IPAddress? ip = parseResult.GetValue(ipOption); int port = parseResult.GetValue(portOption); if (ip == null) { Console.Error.WriteLine("Ошибка: IP адрес не указан или имеет неверный формат"); return 2; } // Запускаем сервер в отдельной задаче var serverTask = Task.Run(() => StartServer(ip, port, _cancellationTokenSource.Token)); Console.WriteLine("Сервер запущен. Введите 'Exit' для остановки..."); // Ждем ввод строки "Exit" в отдельном потоке var exitTask = Task.Run(() => { while (!_cancellationTokenSource.IsCancellationRequested) { var input = Console.ReadLine(); if (!string.IsNullOrEmpty(input) && input.Trim().Equals("Exit", StringComparison.OrdinalIgnoreCase)) { return true; } } return false; }); // Ожидаем либо ввод "Exit", либо завершение сервера var completedTask = await Task.WhenAny(serverTask, exitTask); if (completedTask == exitTask && exitTask.Result) { // Пользователь ввел Exit if (!_cancellationTokenSource.IsCancellationRequested) { Console.WriteLine("Остановка сервера..."); _cancellationTokenSource.Cancel(); _listener?.Stop(); // Даем серверу время на корректное завершение try { await Task.WhenAny(serverTask, Task.Delay(2000)); } catch { // Игнорируем исключения при завершении } Console.WriteLine("Сервер остановлен."); } } else { // Сервер завершился сам (ошибка или другая причина) if (!_cancellationTokenSource.IsCancellationRequested) { _cancellationTokenSource.Cancel(); } Console.WriteLine("Сервер завершил работу."); } return 0; } else { foreach (ParseError parseError in parseResult.Errors) { Console.Error.WriteLine(parseError.Message); } return 1; } } static async Task StartServer(IPAddress ip, int port, CancellationToken cancellationToken) { try { Console.WriteLine($"Запуск сервера на {ip}:{port}"); // Создание TCP listener _listener = new TcpListener(ip, port); _listener.Start(); 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}"); } } } } catch (Exception ex) { if (!cancellationToken.IsCancellationRequested) { Console.WriteLine($"Ошибка: {ex.Message}"); } } finally { try { _listener?.Stop(); } catch { // Игнорируем ошибки при остановке } } } static async Task HandleClient(TcpClient client, CancellationToken cancellationToken) { var clientEndPoint = client.Client.RemoteEndPoint; Console.WriteLine($"Подключен клиент: {clientEndPoint}"); try { using (client) using (var stream = client.GetStream()) using (var reader = new StreamReader(stream, Encoding.UTF8)) using (var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true }) { while (!cancellationToken.IsCancellationRequested) { try { // Чтение строки (до символа новой строки) var line = await reader.ReadLineAsync(); if (line == null) { // Клиент отключился Console.WriteLine($"Клиент отключился: {clientEndPoint}"); break; } Console.WriteLine($"Получено от {clientEndPoint}: {line}"); // Реверсирование строки var reversedString = ReverseString(line); Console.WriteLine($"Отправка: {reversedString}"); // Отправка реверсированной строки обратно клиенту await writer.WriteLineAsync(reversedString); } catch (OperationCanceledException) { // Игнорируем отмену при чтении/записи break; } catch (IOException ex) { // Ошибка ввода/вывода - клиент отключился Console.WriteLine($"Клиент отключился: {clientEndPoint} - {ex.Message}"); break; } } } } catch (Exception ex) when (!cancellationToken.IsCancellationRequested) { Console.WriteLine($"Ошибка при работе с клиентом {clientEndPoint}: {ex.Message}"); } } static string ReverseString(string s) { var charArray = s.ToCharArray(); Array.Reverse(charArray); return new string(charArray); } } }