Compare commits

...

4 Commits

Author SHA1 Message Date
ascet-tomsk
c4fbea36fd Merge branch 'main' of https://git.ahtamov.ru/SharikovPP/LINUX 2026-01-19 02:24:08 +07:00
ascet-tomsk
824e816440 check errors 2026-01-19 02:24:04 +07:00
ascet-tomsk
634ad7e14f изменен протокол 2026-01-19 02:20:13 +07:00
ascet-tomsk
9b79d41f97 add reading server greeting message 2026-01-19 01:01:21 +07:00
4 changed files with 397 additions and 205 deletions

View File

@@ -1,6 +1,7 @@
using System; using System;
using System.CommandLine; using System.CommandLine;
using System.CommandLine.Parsing; using System.CommandLine.Parsing;
using System.IO;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -49,15 +50,13 @@ namespace f_cln
if (!string.IsNullOrEmpty(message)) if (!string.IsNullOrEmpty(message))
{ {
// Режим однократной отправки // Режим однократной отправки
await SendMessage(ip, port, message); return await SendMessage(ip, port, message);
} }
else else
{ {
// Интерактивный режим // Интерактивный режим
await RunInteractive(ip, port); return await RunInteractive(ip, port);
} }
return 0;
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -75,9 +74,7 @@ namespace f_cln
} }
} }
static async Task SendMessage(string ip, int port, string message) static async Task<int> SendMessage(string ip, int port, string message)
{
try
{ {
Console.WriteLine($"Подключение к {ip}:{port}..."); Console.WriteLine($"Подключение к {ip}:{port}...");
@@ -90,32 +87,39 @@ namespace f_cln
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 };
// Читаем приветственное сообщение
var welcomeMessage = await reader.ReadLineAsync();
if (welcomeMessage != null && welcomeMessage.StartsWith("hello "))
{
var clientAddress = welcomeMessage[6..];
Console.WriteLine($"Ваш адрес: {clientAddress}");
}
// Очистка сообщения
string cleanedMessage = CleanInput(message);
Console.WriteLine();
// Отправка сообщения // Отправка сообщения
await writer.WriteLineAsync(message); await writer.WriteLineAsync(cleanedMessage);
Console.WriteLine($"Отправлено: {message}"); Console.WriteLine($"Отправлено: {cleanedMessage}");
// Чтение ответа // Чтение ответа
var response = await reader.ReadLineAsync(); var response = await reader.ReadLineAsync();
if (response != null) if (response != null)
{ {
Console.WriteLine($"Получено: {response}"); string cleanedResponse = CleanInput(response);
Console.WriteLine($"Ответ: {cleanedResponse}");
return 0;
} }
else else
{ {
Console.WriteLine("Сервер не ответил"); Console.WriteLine("Сервер не ответил");
} return 2;
}
catch (SocketException ex)
{
Console.WriteLine($"Сетевая ошибка: {ex.Message}");
throw;
} }
} }
static async Task RunInteractive(string ip, int port) static async Task<int> RunInteractive(string ip, int port)
{
try
{ {
Console.WriteLine($"Подключение к {ip}:{port}..."); Console.WriteLine($"Подключение к {ip}:{port}...");
@@ -123,56 +127,112 @@ namespace f_cln
await client.ConnectAsync(ip, port); await client.ConnectAsync(ip, port);
Console.WriteLine("Подключено к серверу"); Console.WriteLine("Подключено к серверу");
Console.WriteLine("Введите текст для отправки (или 'exit' для выхода):");
using var stream = client.GetStream(); using var stream = client.GetStream();
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 };
// Читаем приветственное сообщение
var welcomeMessage = await reader.ReadLineAsync();
if (welcomeMessage != null && welcomeMessage.StartsWith("hello "))
{
var clientAddress = welcomeMessage[6..];
Console.WriteLine($"Ваш адрес: {clientAddress}");
}
Console.WriteLine(); // Пустая строка для единообразия
PrintHelp();
while (true) while (true)
{ {
// Чтение ввода пользователя try
{
Console.Write("> "); Console.Write("> ");
var input = Console.ReadLine(); var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input)) if (string.IsNullOrWhiteSpace(input))
continue; continue;
if (input.Equals("exit", StringComparison.OrdinalIgnoreCase)) // Очистка ввода от непечатаемых символов и BOM
input = CleanInput(input);
if (string.IsNullOrEmpty(input))
continue;
if (input.Equals("exit", StringComparison.OrdinalIgnoreCase) ||
input.Equals("quit", StringComparison.OrdinalIgnoreCase))
{ {
Console.WriteLine("Завершение работы..."); Console.WriteLine("Завершение работы...");
break; break;
} }
try if (input.Equals("help", StringComparison.OrdinalIgnoreCase))
{ {
PrintHelp();
continue;
}
// Отправка сообщения // Отправка сообщения
await writer.WriteLineAsync(input); await writer.WriteLineAsync(input);
Console.WriteLine($"Отправлено: {input}");
// Чтение ответа // Чтение ответа
var response = await reader.ReadLineAsync(); var response = await reader.ReadLineAsync();
if (response != null) if (response != null)
{ {
// Очистка ответа от непечатаемых символов
response = CleanInput(response);
Console.WriteLine($"Ответ: {response}"); Console.WriteLine($"Ответ: {response}");
} }
else else
{ {
Console.WriteLine("Сервер отключился"); Console.WriteLine("Сервер отключился");
break; return 2;
} }
} }
catch (Exception ex) when (ex is IOException || ex is ObjectDisposedException)
{
Console.WriteLine("Соединение с сервером разорвано");
return 2;
}
catch (Exception ex) catch (Exception ex)
{ {
Console.WriteLine($"Ошибка при отправке/получении: {ex.Message}"); Console.WriteLine($"Ошибка: {ex.Message}");
break; return 2;
} }
} }
return 0;
} }
catch (SocketException ex)
// Метод для очистки строки от непечатаемых символов
static string CleanInput(string input)
{ {
Console.WriteLine($"Ошибка подключения: {ex.Message}"); if (string.IsNullOrEmpty(input))
} return input;
// Удаляем BOM (U+FEFF) и другие непечатаемые символы
var result = new StringBuilder();
foreach (char c in input)
{
// Оставляем только печатаемые символы и пробелы
if (!char.IsControl(c) || c == '\n' || c == '\r' || c == '\t')
{
result.Append(c);
}
}
return result.ToString().Trim();
}
static void PrintHelp()
{
Console.WriteLine("\n=== Команды клиента ===");
Console.WriteLine(" Просто введите текст для отправки на сервер");
Console.WriteLine(" exit или quit - завершить работу");
Console.WriteLine(" help - показать эту справку");
Console.WriteLine("========================\n");
} }
} }
} }

View File

@@ -2,7 +2,7 @@
"profiles": { "profiles": {
"f-cln": { "f-cln": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "-p 1771" "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();
var input = Console.ReadLine();
if (!string.IsNullOrEmpty(input) &&
input.Trim().Equals("Exit", StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
});
// Ожидаем либо ввод "Exit", либо завершение сервера if (string.IsNullOrEmpty(command))
var completedTask = await Task.WhenAny(serverTask, exitTask); continue;
if (completedTask == exitTask && exitTask.Result) switch (command)
{ {
// Пользователь ввел Exit case "старт":
if (!_cancellationTokenSource.IsCancellationRequested) if (!_isRunning)
{ {
Console.WriteLine("Остановка сервера..."); await StartServer(ip, port);
_cancellationTokenSource.Cancel(); _isRunning = true;
_listener?.Stop(); Console.WriteLine("Сервер запущен");
// Даем серверу время на корректное завершение
try
{
await Task.WhenAny(serverTask, Task.Delay(2000));
}
catch
{
// Игнорируем исключения при завершении
}
Console.WriteLine("Сервер остановлен.");
}
} }
else else
{ {
// Сервер завершился сам (ошибка или другая причина) Console.WriteLine("Сервер уже запущен");
if (!_cancellationTokenSource.IsCancellationRequested)
{
_cancellationTokenSource.Cancel();
} }
Console.WriteLine("Сервер завершил работу."); break;
case "стоп":
if (_isRunning)
{
await StopServer();
_isRunning = false;
Console.WriteLine("Сервер остановлен");
}
else
{
Console.WriteLine("Сервер уже остановлен");
}
break;
case "пауза":
if (_isRunning && !_isPaused)
{
_isPaused = true;
Console.WriteLine("Сервер приостановлен. Новые подключения не обрабатываются.");
}
else if (!_isRunning)
{
Console.WriteLine("Сервер не запущен");
}
else
{
Console.WriteLine("Сервер уже приостановлен");
}
break;
case "продолжить":
if (_isRunning && _isPaused)
{
_isPaused = false;
Console.WriteLine("Сервер возобновил работу");
}
else if (!_isRunning)
{
Console.WriteLine("Сервер не запущен");
}
else
{
Console.WriteLine("Сервер уже работает");
}
break;
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; return 0;
case "помощь":
case "help":
PrintHelp();
break;
default:
Console.WriteLine($"Неизвестная команда: {command}");
Console.WriteLine("Введите 'помощь' для списка команд");
break;
}
}
} }
else else
{ {
@@ -145,38 +188,56 @@ 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());
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка при запуске сервера: {ex.Message}");
throw;
}
}
static async Task AcceptConnectionsAsync()
{
while (!_cancellationTokenSource.Token.IsCancellationRequested)
{ {
try try
{ {
// Ожидание подключения клиента с таймаутом для проверки отмены // Если сервер на паузе, ждем
var acceptTask = _listener.AcceptTcpClientAsync(); if (_isPaused)
var completedTask = await Task.WhenAny(acceptTask, Task.Delay(1000, cancellationToken));
if (completedTask == acceptTask && !cancellationToken.IsCancellationRequested)
{ {
var client = await acceptTask; await Task.Delay(1000);
continue;
}
// Ожидание подключения клиента
var client = await _listener!.AcceptTcpClientAsync();
lock (_lockObject)
{
_connectedClients.Add(client);
}
// Обработка клиента в отдельной задаче // Обработка клиента в отдельной задаче
_ = Task.Run(async () => await HandleClient(client, cancellationToken)); _ = Task.Run(async () => await HandleClient(client));
}
}
catch (OperationCanceledException)
{
// Игнорируем отмену
break;
} }
catch (ObjectDisposedException) catch (ObjectDisposedException)
{ {
@@ -185,34 +246,15 @@ namespace f_srv
} }
catch (Exception ex) catch (Exception ex)
{ {
if (!cancellationToken.IsCancellationRequested) if (!_cancellationTokenSource.Token.IsCancellationRequested)
{ {
Console.WriteLine($"Ошибка при принятии подключения: {ex.Message}"); 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) 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)

View File

@@ -2,7 +2,7 @@
"profiles": { "profiles": {
"f-srv": { "f-srv": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "--port 3113 -i 192.168.15.128" "commandLineArgs": "--port 1771 -i 127.0.1.1"
} }
} }
} }