diff --git a/Server/Server/Server.sln b/Server/Server/Server.sln
new file mode 100644
index 0000000..2dd624e
--- /dev/null
+++ b/Server/Server/Server.sln
@@ -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
diff --git a/Server/Server/Server/Client.cs b/Server/Server/Server/Client.cs
new file mode 100644
index 0000000..821e2e1
--- /dev/null
+++ b/Server/Server/Server/Client.cs
@@ -0,0 +1,106 @@
+namespace Server;
+
+using System.Net.Sockets;
+using System.Net;
+
+///
+/// Сlass representing the client
+///
+public class Client
+{
+ private readonly int port;
+ private readonly IPAddress address;
+
+ ///
+ /// Сonstructor
+ ///
+ /// ip adress
+ /// port
+ public Client(IPAddress adress, int port)
+ {
+ this.port = port;
+ this.address = adress;
+ }
+
+ ///
+ /// Method for listing files
+ ///
+ /// stream
+ /// path to directory
+ ///
+ public async Task<(int, List<(string, bool)>)> List(string pathToDiretory)
+ {
+ var client = new TcpClient();
+
+ // Подключаемся к узлу
+ await client.ConnectAsync(address, port);
+
+ // Получаем поток для записи и чтения
+ using var stream = client.GetStream();
+
+
+ using var streamWriter = new StreamWriter(stream) { AutoFlush = true };
+
+ // Отправляем сообщение подключенному tcpсерверу.
+ await streamWriter.WriteLineAsync($"list {pathToDiretory}");
+ 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);
+ }
+
+ ///
+ /// Method for get files
+ ///
+ /// stream
+ /// path to file
+ ///
+ 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());
+ if (!int.TryParse(stringWithSize, out int size))
+ {
+ throw new InvalidDataException();
+ }
+
+ if (size == -1)
+ {
+ throw new FileNotFoundException();
+ }
+
+ var buffer = new byte[size];
+ await streamReader.BaseStream.ReadAsync(buffer, 0, size);
+ return (size, buffer);
+ }
+}
diff --git a/Server/Server/Server/Server.cs b/Server/Server/Server/Server.cs
new file mode 100644
index 0000000..68b4330
--- /dev/null
+++ b/Server/Server/Server/Server.cs
@@ -0,0 +1,133 @@
+namespace Server;
+
+using System.Net.Sockets;
+using System.Net;
+
+///
+/// Class representing the server
+///
+public class Server
+{
+ private readonly int port;
+ private readonly IPAddress address;
+
+ ///
+ /// Сonstructor
+ ///
+ /// ip adress
+ /// port
+ public Server(IPAddress adress, int port)
+ {
+ this.address = adress;
+ this.port = port;
+ }
+
+ ///
+ /// Method for listing files
+ ///
+ /// stream
+ /// path to directory
+ ///
+ 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");
+ }
+ }
+
+ ///
+ /// Method for get files
+ ///
+ /// stream
+ /// path to file
+ ///
+ 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;
+ await streamWriter.WriteLineAsync(size.ToString());
+ using var fileStream = new FileStream(path, FileMode.Open);
+ await fileStream.CopyToAsync(streamWriter.BaseStream);
+ }
+
+ ///
+ /// Function to start the server (it will start listening for connections from clients)
+ ///
+ ///
+ 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() =>
+ {
+ // Поток для записи и чтения в полученный сокет
+ 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();
+ });
+ }
+
+ tcpListener.Stop();
+ }
+}
\ No newline at end of file
diff --git a/Server/Server/Server/Server.csproj b/Server/Server/Server/Server.csproj
new file mode 100644
index 0000000..74abf5c
--- /dev/null
+++ b/Server/Server/Server/Server.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net6.0
+ enable
+ enable
+
+
+
diff --git a/Server/Server/Server/Solution.cs b/Server/Server/Server/Solution.cs
new file mode 100644
index 0000000..5ddf08d
--- /dev/null
+++ b/Server/Server/Server/Solution.cs
@@ -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();
+var serverTask = Task.Run(() => server.Start(cancelTokenSource), cancelTokenSource.Token);
+var client = new Server.Client(ip!, port);
+
+for (int i = 2; i < args.Length; i++)
+{
+ switch(args[i])
+ {
+ case "list":
+ {
+ var (size, names) = await Task.Run(() => client.List(args[i + 1]));
+ 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]);
+ }
+ Console.WriteLine();
+ i++;
+ break;
+ }
+ default:
+ {
+ i++;
+ continue;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Server/Server/ServerTest/Files/azaza.txt b/Server/Server/ServerTest/Files/azaza.txt
new file mode 100644
index 0000000..4912f24
--- /dev/null
+++ b/Server/Server/ServerTest/Files/azaza.txt
@@ -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
\ No newline at end of file
diff --git a/Server/Server/ServerTest/Files/uzuzu.txt b/Server/Server/ServerTest/Files/uzuzu.txt
new file mode 100644
index 0000000..e69de29
diff --git a/Server/Server/ServerTest/ServerTest.cs b/Server/Server/ServerTest/ServerTest.cs
new file mode 100644
index 0000000..46f56d2
--- /dev/null
+++ b/Server/Server/ServerTest/ServerTest.cs
@@ -0,0 +1,52 @@
+namespace ServerTest;
+
+using System.Net;
+using Server;
+
+public class Tests
+{
+ Server? server;
+
+ [SetUp]
+ public void Setup()
+ {
+ server = new Server(IPAddress.Loopback, 10000);
+ var cancelTokenSource = new CancellationTokenSource();
+ var serverTask = Task.Run(() => server.Start(cancelTokenSource), cancelTokenSource.Token);
+ }
+
+ [Test]
+ public void ShouldExpectedDirectoryNotFoundExceptionIfListForNonExistentDirectory()
+ {
+ var client = new Client(IPAddress.Loopback, 10000);
+ Assert.ThrowsAsync(() => client.List("./NonExistentDirectory"));
+ }
+
+ [Test]
+ public void ShouldExpectedFileNotFoundExceptionIfGetForNonExistentFile()
+ {
+ var client = new Client(IPAddress.Loopback, 10000);
+ Assert.ThrowsAsync(() => client.Get("NonExistentFile.txt"));
+ }
+
+ [Test]
+ public async Task ShouldExpectedThatMultipleClientsCanAccessTheFile()
+ {
+ var firstClient = new Client(IPAddress.Loopback, 10000);
+ var secondClient = new Client(IPAddress.Loopback, 10000);
+ var thirdClient = new Client(IPAddress.Loopback, 10000);
+ var firstTask = firstClient.Get("..//..//..//Files//azaza.txt");
+ var secondTask = secondClient.Get("..//..//..//Files//azaza.txt");
+ var thirdTask = thirdClient.Get("..//..//..//Files//azaza.txt");
+ var (firstSize, firstBytes) = await firstTask;
+ var (secondSize, secondBytes) = await secondTask;
+ var (thirdSize, thirdBytes) = await thirdTask;
+ Assert.Multiple(() =>
+ {
+ Assert.That(firstSize, Is.EqualTo(secondSize));
+ Assert.That(firstSize, Is.EqualTo(thirdSize));
+ Assert.That(firstBytes, Is.EquivalentTo(secondBytes));
+ Assert.That(firstBytes, Is.EquivalentTo(thirdBytes));
+ });
+ }
+}
diff --git a/Server/Server/ServerTest/ServerTest.csproj b/Server/Server/ServerTest/ServerTest.csproj
new file mode 100644
index 0000000..7f4db5a
--- /dev/null
+++ b/Server/Server/ServerTest/ServerTest.csproj
@@ -0,0 +1,23 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Server/Server/ServerTest/Usings.cs b/Server/Server/ServerTest/Usings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/Server/Server/ServerTest/Usings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file