Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions thirdTestTask/thirdTestTask.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.13.35806.99 d17.13
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "thirdTestTask", "thirdTestTask\thirdTestTask.csproj", "{0B8D0C96-1815-4C28-962A-89EEA36DAC6C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0B8D0C96-1815-4C28-962A-89EEA36DAC6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B8D0C96-1815-4C28-962A-89EEA36DAC6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B8D0C96-1815-4C28-962A-89EEA36DAC6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B8D0C96-1815-4C28-962A-89EEA36DAC6C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B5862231-4F8A-4732-BBF1-C911C3298007}
EndGlobalSection
EndGlobal
50 changes: 50 additions & 0 deletions thirdTestTask/thirdTestTask/App.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Подозреваю, что тут много ненужных using-ов, и их лучше внутри namespace писать


namespace thirdTestTask;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Пространства имён в .NET именуются с заглавной всегда


public static class App

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Комментариев не хватает

{
public static async Task<int> Run(string[] args)
{
if (TryParseServer(args, out int serverPort))
{
await ServerHost.RunOnce(serverPort);
return 0;
}

if (TryParseClient(args, out IPAddress? ip, out int clientPort))
{
await ClientHost.Run(ip!, clientPort);
return 0;
}

PrintUsage();
return 2;
}

private static bool TryParseServer(string[] args, out int port)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out-переменные — большая редкость в современном C#, где есть кортежи. Это нейросеть так пишет? :)

{
port = 0;
return args.Length == 1 && int.TryParse(args[0], out port);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Стоило бы заодно проверить, принадлежит ли номер порта разрешённому диапазону.

}

private static bool TryParseClient(string[] args, out IPAddress? ip, out int port)
{
ip = null;
port = 0;

return args.Length == 2 && IPAddress.TryParse(args[0], out ip) && int.TryParse(args[1], out port);
}

private static void PrintUsage()
{
Console.WriteLine("Использование:");
Console.WriteLine("Сервер: <port>");
Console.WriteLine("Клиент: <ip> <port>");
}
}
114 changes: 114 additions & 0 deletions thirdTestTask/thirdTestTask/ChatSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Text.Unicode;
using System.Threading.Tasks;

namespace thirdTestTask;

public static class ChatSession
{
public static async Task RunAsync(TcpClient client, TextReader input, TextWriter output, CancellationToken token = default)
{
using var cts = CancellationTokenSource.CreateLinkedTokenSource(token);
CancellationToken token2 = cts.Token;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Что-то сложно. Можно было дальше cts.Token и использовать


NetworkStream stream = client.GetStream();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using? Клиент сам его закроет, но вообще NetworkStream IDisposable, поэтому можно дать ему самому разобраться, когда надо закрыться


using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: true);
using var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 1024, leaveOpen: true){ AutoFlush = true };
Task receiveTask = Task.Run(async () =>
{
try
{
while (!token2.IsCancellationRequested)
{
string? msg = await reader.ReadLineAsync();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Сюда бы тоже CancellationToken, чтобы мы не ждали вечно сообщения


if (msg == null)
{
await SafeWriteLineAsync(output, "\n[СИСТЕМА] Соединение разорвано.");
cts.Cancel();
break;
}

if (IsExit(msg))
{
await SafeWriteLineAsync(output, "\n[СИСТЕМА] Собеседник завершил чат.");
cts.Cancel();
break;
}

await SafeWriteLineAsync(output, $"[Собеседник]: {msg}");
}
}
catch
{
cts.Cancel();
}
}, token2);

Task sendTask = Task.Run(async () =>
{
try
{
while (!token2.IsCancellationRequested)
{
string? line = await ReadLineWithCancelAsync(input, token2);

if (line == null)
{
cts.Cancel();
break;
}

if (string.IsNullOrWhiteSpace(line))
continue;

await writer.WriteLineAsync(line);

if (IsExit(line))
{
cts.Cancel();
break;
}
}
}
catch
{
cts.Cancel();
}
}, token2);

await Task.WhenAny(receiveTask, sendTask);

try { client.Close(); }
catch { }

cts.Cancel();
try { await Task.WhenAll(receiveTask, sendTask); }
catch { }
}

private static bool IsExit(string s)
=> s.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase);

private static Task SafeWriteLineAsync(TextWriter output, string text)
{
output.WriteLine(text);
output.Flush();
return Task.CompletedTask;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну такое это async. Выглядит как обман почтенной публики, операция выполняется синхронно

}

private static async Task<string?> ReadLineWithCancelAsync(TextReader input, CancellationToken token)
{
Task<string?> readTask = input.ReadLineAsync();
Task done = await Task.WhenAny(readTask, Task.Delay(Timeout.Infinite, token));

if (done != readTask) return null;
return await readTask;
}
}

25 changes: 25 additions & 0 deletions thirdTestTask/thirdTestTask/ClientHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace thirdTestTask;

public static class ClientHost
{
public static async Task Run(IPAddress ip, int port)
{
using var client = new TcpClient();

Console.WriteLine($"[Клиент] подключение к {ip}: {port} ");
await client.ConnectAsync(ip, port);

Console.WriteLine("[Клиент] подключено. Для выхода - exit");
await ChatSession.RunAsync(client, Console.In, Console.Out);

Console.WriteLine("[Клиент] завершение");
}
}
3 changes: 3 additions & 0 deletions thirdTestTask/thirdTestTask/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using thirdTestTask;

await App.Run(args);
34 changes: 34 additions & 0 deletions thirdTestTask/thirdTestTask/ServerHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace thirdTestTask;

public static class ServerHost
{
public static async Task RunOnce(int port)
{
var listner = new TcpListener(IPAddress.Any, port);
listner.Start();

try
{
Console.WriteLine($"[Сервер] Ожидание подлюкчения на порту {port}...");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Console.WriteLine($"[Сервер] Ожидание подлюкчения на порту {port}...");
Console.WriteLine($"[Сервер] Ожидание подключения на порту {port}...");


using TcpClient client = await listner.AcceptTcpClientAsync();

Console.WriteLine("[Сервер] Клиент подключился. Для выхода - exit");
await ChatSession.RunAsync(client, Console.In, Console.Out);
}

finally
{
listner.Stop();
Console.WriteLine("[Сервер] Завершение");
}
}
}
10 changes: 10 additions & 0 deletions thirdTestTask/thirdTestTask/thirdTestTask.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StyleCop бы ещё


</Project>