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
31 changes: 31 additions & 0 deletions Server/Server/Server.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32505.173
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{A00779F1-A313-4AFA-9CA9-FC8751E23609}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerTest", "ServerTest\ServerTest.csproj", "{466C5BB4-D15D-47CE-84BE-6A52D07040CC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A00779F1-A313-4AFA-9CA9-FC8751E23609}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A00779F1-A313-4AFA-9CA9-FC8751E23609}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A00779F1-A313-4AFA-9CA9-FC8751E23609}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A00779F1-A313-4AFA-9CA9-FC8751E23609}.Release|Any CPU.Build.0 = Release|Any CPU
{466C5BB4-D15D-47CE-84BE-6A52D07040CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{466C5BB4-D15D-47CE-84BE-6A52D07040CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{466C5BB4-D15D-47CE-84BE-6A52D07040CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{466C5BB4-D15D-47CE-84BE-6A52D07040CC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E304F713-BA15-432A-8DB6-6474FD71D207}
EndGlobalSection
EndGlobal
106 changes: 106 additions & 0 deletions Server/Server/Server/Client.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
namespace Server;

using System.Net.Sockets;
using System.Net;

/// <summary>
/// Сlass representing the client
/// </summary>
public class Client
{
private readonly int port;
private readonly IPAddress address;

/// <summary>
/// Сonstructor
/// </summary>
/// <param name="adress">ip adress</param>
/// <param name="port">port</param>
public Client(IPAddress adress, int port)
{
this.port = port;
this.address = adress;
}

/// <summary>
/// Method for listing files
/// </summary>
/// <param name="stream">stream</param>
/// <param name="path">path to directory</param>
/// <returns></returns>

Choose a reason for hiding this comment

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

Пустые тэги не нужны

public async Task<(int, List<(string, bool)>)> List(string pathToDiretory)
{
var client = new TcpClient();

// Подключаемся к узлу
await client.ConnectAsync(address, port);

// Получаем поток для записи и чтения
using var stream = client.GetStream();


Choose a reason for hiding this comment

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

Две пустые строки подряд — тоже :)

using var streamWriter = new StreamWriter(stream) { AutoFlush = true };

// Отправляем сообщение подключенному tcpсерверу.
await streamWriter.WriteLineAsync($"list {pathToDiretory}");

Choose a reason for hiding this comment

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

Нарушение протокола, list в условии кодируется единицей

using var streamReader = new StreamReader(stream);

// Получаем ответ от сервера
var data = await streamReader.ReadLineAsync();
if (data == null)
{
throw new InvalidDataException();
}

var strings = data.Split(' ');
if (!int.TryParse(strings[0], out int size))
{
throw new InvalidDataException();
}

if (size == -1)
{
throw new DirectoryNotFoundException();
}

var list = new List<(string, bool)>();
for (int i = 1; i < strings.Length; i++)
{
bool flag = strings[i + 1] != "false";
list.Add((strings[i], flag));
i++;
}

return (size, list);

Choose a reason for hiding this comment

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

Список сам знает свой размер, так что size несколько избыточен

}

/// <summary>
/// Method for get files
/// </summary>
/// <param name="stream">stream</param>
/// <param name="path">path to file</param>
/// <returns></returns>
public async Task<(int, byte[])> Get(string pathToFile)
{
var client = new TcpClient();
await client.ConnectAsync(address, port);
using var stream = client.GetStream();
using var streamWriter = new StreamWriter(stream) { AutoFlush = true };
await streamWriter.WriteLineAsync($"get {pathToFile}");
using var streamReader = new StreamReader(stream);
var stringWithSize = (await streamReader.ReadLineAsync());

Choose a reason for hiding this comment

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

Скобки не нужны

if (!int.TryParse(stringWithSize, out int size))
{
throw new InvalidDataException();
}

if (size == -1)
{
throw new FileNotFoundException();
}

var buffer = new byte[size];

Choose a reason for hiding this comment

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

Тут лучше CopyToAsync и в память не писать (а принимать стрим в Get). Потому что файлы могут быть большими

await streamReader.BaseStream.ReadAsync(buffer, 0, size);
return (size, buffer);

Choose a reason for hiding this comment

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

И тут. Массив тоже знает свой размер

}
}
133 changes: 133 additions & 0 deletions Server/Server/Server/Server.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
namespace Server;

using System.Net.Sockets;
using System.Net;

/// <summary>
/// Class representing the server
/// </summary>
public class Server
{
private readonly int port;
private readonly IPAddress address;

/// <summary>
/// Сonstructor
/// </summary>
/// <param name="adress">ip adress</param>
/// <param name="port">port</param>
public Server(IPAddress adress, int port)
{
this.address = adress;
this.port = port;
}

/// <summary>
/// Method for listing files
/// </summary>
/// <param name="stream">stream</param>
/// <param name="path">path to directory</param>
/// <returns></returns>
private static async Task List(NetworkStream stream, string path)
{
using var streamWriter = new StreamWriter(stream) { AutoFlush = true };

if (!Directory.Exists(path))
{
await streamWriter.WriteAsync("-1");
return;
}

var directories = Directory.GetDirectories(path);
var files = Directory.GetFiles(path);
var size = directories.Length + files.Length;

await streamWriter.WriteAsync(size.ToString());

foreach (var file in files)
{
await streamWriter.WriteAsync($" {file} false");
}

foreach (var directory in directories)
{
await streamWriter.WriteAsync($" {directory} true");
}
}

/// <summary>
/// Method for get files
/// </summary>
/// <param name="stream">stream</param>
/// <param name="path">path to file</param>
/// <returns></returns>
private static async Task Get(NetworkStream stream, string path)
{
using var streamWriter = new StreamWriter(stream) { AutoFlush = true };
if (!File.Exists(path))
{
await streamWriter.WriteAsync("-1");
return;
}

var size = (new FileInfo(path)).Length;

Choose a reason for hiding this comment

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

Тут тоже лишние скобки

await streamWriter.WriteLineAsync(size.ToString());
using var fileStream = new FileStream(path, FileMode.Open);
await fileStream.CopyToAsync(streamWriter.BaseStream);
}

/// <summary>
/// Function to start the server (it will start listening for connections from clients)
/// </summary>
/// <returns></returns>
public async Task Start(CancellationTokenSource source)
{
var tcpListener = new TcpListener(address, port);

// Слушаем порт
tcpListener.Start();

while (!source.Token.IsCancellationRequested)
{
// Блокируем поток до установления соединения
var acceptedSocket = await tcpListener.AcceptSocketAsync();

// Каждый клиент обслуживается в своем потоке. Т.к. async, то не будет блокировок при чтении больших файлов
await Task.Run(async() =>

Choose a reason for hiding this comment

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

Не, await и Task.Run — это взаимнообратные операции. Так мы всё равно не сможем обслужить второго клиента, пока первый не отключится. Надо создать таск, и пусть он работает, а мы пока будем слушать новые подключения

{
// Поток для записи и чтения в полученный сокет
using var newtworkStream = new NetworkStream(acceptedSocket);

// Получаем сообщение от клиента
using var streamReader = new StreamReader(newtworkStream);
var strings = (streamReader.ReadLine())?.Split(' ');
if (strings == null)
{
throw new InvalidDataException();
}

switch (strings[0])
{
case "list":
{
await List(newtworkStream, strings[1]);
break;
}
case "get":
{
await Get(newtworkStream, strings[1]);
break;
}
default:
{
throw new InvalidDataException();
}
}

acceptedSocket.Close();

Choose a reason for hiding this comment

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

Надо было using (acceptedSocket) { ... }, иначе этот код небезопасен с точки зрения исключений

});
}

tcpListener.Stop();
}
}
10 changes: 10 additions & 0 deletions Server/Server/Server/Server.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>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

</Project>
72 changes: 72 additions & 0 deletions Server/Server/Server/Solution.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System.Net;

Console.WriteLine("Формат ввода через командную строку");
Console.WriteLine("string: IPaddress");
Console.WriteLine("int: IPaddress");
Console.WriteLine($"get string :path to file");
Console.WriteLine($"list string :path to directory");
Console.WriteLine($"Например: {"127.0.0.1"} {"80"} {"list ./File"} {"get ./File/File.txt"}");

if (args.Length < 3)
{
return;
}

if (!IPAddress.TryParse(args[0], out IPAddress? ip))
{
Console.WriteLine("incorrect ip address input");
return;
}

if (!int.TryParse(args[1], out int port))
{
Console.WriteLine("incorrect port input");
return;
}

if (port < 1024 || port > 65535)
{
Console.WriteLine("incorrect port input");
return;
}

var server = new Server.Server(ip!, port);
var cancelTokenSource = new CancellationTokenSource();

Choose a reason for hiding this comment

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

По-хорошему, сервер надо остановить в конце и дождаться остановки

var serverTask = Task.Run(() => server.Start(cancelTokenSource), cancelTokenSource.Token);
var client = new Server.Client(ip!, port);
Comment on lines +33 to +36

Choose a reason for hiding this comment

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

Очень странно запускать сразу и сервер и клиент.Система сама с собой по сети общается?


for (int i = 2; i < args.Length; i++)
{
switch(args[i])

Choose a reason for hiding this comment

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

Suggested change
switch(args[i])
switch (args[i])

{
case "list":
{
var (size, names) = await Task.Run(() => client.List(args[i + 1]));

Choose a reason for hiding this comment

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

Suggested change
var (size, names) = await Task.Run(() => client.List(args[i + 1]));
var (size, names) = await client.List(args[i + 1]);

async-методы и так Task всегда возвращают, уже исполняющийся. Оборачивать их с помощью Task.Run нет смысла. Тут и много где ещё.

Console.WriteLine($"size : {size}");
for (int j = 0; j < names.Count; j++)
{
Console.Write(names[j]);
Console.WriteLine();
}
i++;
break;
}
case "get":
{
var(size, bytes) = await Task.Run(() => client.Get(args[i + 1]));
Console.WriteLine($"size : {size}");
for (int j = 0; j < bytes.Length; j++)
{
Console.Write(bytes[j]);

Choose a reason for hiding this comment

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

Не, надо бы в файл писать

}
Console.WriteLine();
i++;
break;
}
default:
{
i++;
continue;
}
}
}
1 change: 1 addition & 0 deletions Server/Server/ServerTest/Files/azaza.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dewdewdewdwef wee v vev vjev dvied vd vdsv dvd vd vd df dfiv dfvedvbaev aevea beab deobed beb ervbew vv ebveivbe besba sD bdf bdf bdfbfdb df fdbfdb fd df df bjer jejberb ebe be rber bb boerivb er ibb erbervber vbrbvj jeb ev e e idfb fdivdfmvi mivdfvmidfvim mmidfvmiifvimfm idfmvmfdvmdfivmifimdimvimf mimdfivmdfiv miadmiviabjiaibvdafjibjid indfinvindfndfin idn idifdibijdfjbifd idfvjiijfbjidfaij idfbidfi d df bidf daf df fvdfvdfiiodfmo dfufdn ndfuudjivjdfbjiijoadfn adfinbdafibjvadfibjdafi iadjbjiadijbdaibnn idfiidfjbjidjibadijijodb idafbidjafjbidjoi dfjibdfibidfjij dfjivjdfjiboi dfivjdfbjidij dfijbjiodfjibdnirtbib inirjtnijrtjn ijtrbjiribr ibijbrtbiijtrbjrtbjiibrjibtrbtbijoiojriojiijijtij rtbtjibibdindinbi ninnitniintrhintinbnibntrnithtnr htrirtib jin ihtrjnb b bitrb ijb bijtbf brb rbb nbnjb tbnjtr btnb tbn tbntrjbnjnb btjnbtrjnbjtrbntrnbr btrjnbntbjtrb trjnbniorbnooithiorbirbj ibirbnoiernib
Empty file.
Loading