Files
LINUX/f-srv/Program.cs

228 lines
9.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<int> Main(string[] args)
{
// Создание команды с аргументами
Option<IPAddress> ipOption = new("address", new[] { "--ip", "-i" })
{
Description = "IP адрес для прослушивания (по умолчанию: все интерфейсы)",
DefaultValueFactory = parseResult => IPAddress.Any
};
Option<int> portOption = new("port", new[] { "--port", "-p" })
{
Description = "Порт для прослушивания (по умолчанию: 1771)",
DefaultValueFactory = parseResult => 1771
};
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("Сервер запущен. Нажмите любую клавишу для остановки...");
// Ждем нажатия клавиши в отдельном потоке
var keyTask = Task.Run(() =>
{
Console.ReadKey(true); // true - не отображать нажатую клавишу
return true;
});
// Ожидаем либо нажатия клавиши, либо завершения сервера
await Task.WhenAny(serverTask, keyTask);
if (!_cancellationTokenSource.IsCancellationRequested)
{
// Отправляем сигнал отмены
_cancellationTokenSource.Cancel();
// Останавливаем listener
_listener?.Stop();
// Даем серверу время на корректное завершение
try
{
await Task.WhenAny(serverTask, Task.Delay(2000));
}
catch
{
// Игнорируем исключения при завершении
}
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);
}
}
}