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.CommandLine;
using System.CommandLine.Parsing;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
@@ -49,15 +50,13 @@ namespace f_cln
if (!string.IsNullOrEmpty(message))
{
// Режим однократной отправки
await SendMessage(ip, port, message);
return await SendMessage(ip, port, message);
}
else
{
// Интерактивный режим
await RunInteractive(ip, port);
return await RunInteractive(ip, port);
}
return 0;
}
catch (Exception ex)
{
@@ -75,104 +74,165 @@ 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}...");
using var client = new TcpClient();
await client.ConnectAsync(ip, port);
Console.WriteLine("Подключено к серверу");
using var stream = client.GetStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
using var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
// Читаем приветственное сообщение
var welcomeMessage = await reader.ReadLineAsync();
if (welcomeMessage != null && welcomeMessage.StartsWith("hello "))
{
Console.WriteLine($"Подключение к {ip}:{port}...");
using var client = new TcpClient();
await client.ConnectAsync(ip, port);
Console.WriteLine("Подключено к серверу");
using var stream = client.GetStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
using var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
// Отправка сообщения
await writer.WriteLineAsync(message);
Console.WriteLine($"Отправлено: {message}");
// Чтение ответа
var response = await reader.ReadLineAsync();
if (response != null)
{
Console.WriteLine($"Получено: {response}");
}
else
{
Console.WriteLine("Сервер не ответил");
}
var clientAddress = welcomeMessage[6..];
Console.WriteLine($"Ваш адрес: {clientAddress}");
}
catch (SocketException ex)
// Очистка сообщения
string cleanedMessage = CleanInput(message);
Console.WriteLine();
// Отправка сообщения
await writer.WriteLineAsync(cleanedMessage);
Console.WriteLine($"Отправлено: {cleanedMessage}");
// Чтение ответа
var response = await reader.ReadLineAsync();
if (response != null)
{
Console.WriteLine($"Сетевая ошибка: {ex.Message}");
throw;
string cleanedResponse = CleanInput(response);
Console.WriteLine($"Ответ: {cleanedResponse}");
return 0;
}
else
{
Console.WriteLine("Сервер не ответил");
return 2;
}
}
static async Task RunInteractive(string ip, int port)
static async Task<int> RunInteractive(string ip, int port)
{
try
Console.WriteLine($"Подключение к {ip}:{port}...");
using var client = new TcpClient();
await client.ConnectAsync(ip, port);
Console.WriteLine("Подключено к серверу");
using var stream = client.GetStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
using var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
// Читаем приветственное сообщение
var welcomeMessage = await reader.ReadLineAsync();
if (welcomeMessage != null && welcomeMessage.StartsWith("hello "))
{
Console.WriteLine($"Подключение к {ip}:{port}...");
var clientAddress = welcomeMessage[6..];
Console.WriteLine($"Ваш адрес: {clientAddress}");
}
using var client = new TcpClient();
await client.ConnectAsync(ip, port);
Console.WriteLine(); // Пустая строка для единообразия
PrintHelp();
Console.WriteLine("Подключено к серверу");
Console.WriteLine("Введите текст для отправки (или 'exit' для выхода):");
using var stream = client.GetStream();
using var reader = new StreamReader(stream, Encoding.UTF8);
using var writer = new StreamWriter(stream, Encoding.UTF8) { AutoFlush = true };
while (true)
while (true)
{
try
{
// Чтение ввода пользователя
Console.Write("> ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input))
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("Завершение работы...");
break;
}
try
if (input.Equals("help", StringComparison.OrdinalIgnoreCase))
{
// Отправка сообщения
await writer.WriteLineAsync(input);
// Чтение ответа
var response = await reader.ReadLineAsync();
if (response != null)
{
Console.WriteLine($"Ответ: {response}");
}
else
{
Console.WriteLine("Сервер отключился");
break;
}
PrintHelp();
continue;
}
catch (Exception ex)
// Отправка сообщения
await writer.WriteLineAsync(input);
Console.WriteLine($"Отправлено: {input}");
// Чтение ответа
var response = await reader.ReadLineAsync();
if (response != null)
{
Console.WriteLine($"Ошибка при отправке/получении: {ex.Message}");
break;
// Очистка ответа от непечатаемых символов
response = CleanInput(response);
Console.WriteLine($"Ответ: {response}");
}
else
{
Console.WriteLine("Сервер отключился");
return 2;
}
}
catch (Exception ex) when (ex is IOException || ex is ObjectDisposedException)
{
Console.WriteLine("Соединение с сервером разорвано");
return 2;
}
catch (Exception ex)
{
Console.WriteLine($"Ошибка: {ex.Message}");
return 2;
}
}
catch (SocketException ex)
return 0;
}
// Метод для очистки строки от непечатаемых символов
static string CleanInput(string input)
{
if (string.IsNullOrEmpty(input))
return input;
// Удаляем BOM (U+FEFF) и другие непечатаемые символы
var result = new StringBuilder();
foreach (char c in input)
{
Console.WriteLine($"Ошибка подключения: {ex.Message}");
// Оставляем только печатаемые символы и пробелы
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": {
"f-cln": {
"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.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<TcpClient> _connectedClients = new List<TcpClient>();
private static bool _isRunning = false;
static async Task<int> Main(string[] args)
{
@@ -20,44 +26,13 @@ namespace f_srv
Option<IPAddress> 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<int> 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)

View File

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