From d8bc16f14162b7f78f2c2be137638bc03588768d Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 2 Nov 2022 22:52:37 +0300 Subject: [PATCH 1/5] Server, Client classes are written Added tests and comments --- Server/Server/Server.sln | 31 ++++++ Server/Server/Server/Client.cs | 96 ++++++++++++++++ Server/Server/Server/Server.cs | 124 +++++++++++++++++++++ Server/Server/Server/Server.csproj | 10 ++ Server/Server/Server/Solution.cs | 66 +++++++++++ Server/Server/ServerTest/Files/azaza.txt | 1 + Server/Server/ServerTest/Files/uzuzu.txt | 0 Server/Server/ServerTest/ServerTest.cs | 66 +++++++++++ Server/Server/ServerTest/ServerTest.csproj | 23 ++++ Server/Server/ServerTest/Usings.cs | 1 + 10 files changed, 418 insertions(+) create mode 100644 Server/Server/Server.sln create mode 100644 Server/Server/Server/Client.cs create mode 100644 Server/Server/Server/Server.cs create mode 100644 Server/Server/Server/Server.csproj create mode 100644 Server/Server/Server/Solution.cs create mode 100644 Server/Server/ServerTest/Files/azaza.txt create mode 100644 Server/Server/ServerTest/Files/uzuzu.txt create mode 100644 Server/Server/ServerTest/ServerTest.cs create mode 100644 Server/Server/ServerTest/ServerTest.csproj create mode 100644 Server/Server/ServerTest/Usings.cs 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..6bfa543 --- /dev/null +++ b/Server/Server/Server/Client.cs @@ -0,0 +1,96 @@ +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); + await streamWriter.WriteLineAsync($"list {pathToDiretory}"); + await streamWriter.FlushAsync(); + 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 = true; + if (strings[i + 1] == "false") + { + flag = 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..14bdba3 --- /dev/null +++ b/Server/Server/Server/Server.cs @@ -0,0 +1,124 @@ +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); + + if (!Directory.Exists(path)) + { + await streamWriter.WriteAsync("-1"); + await streamWriter.FlushAsync(); + return; + } + + var directories = Directory.GetDirectories(path); + var files = Directory.GetFiles(path); + var size = directories.Length + files.Length; + await streamWriter.WriteAsync(size.ToString()); + await streamWriter.FlushAsync(); + + foreach (var file in files) + { + await streamWriter.WriteAsync($" {file} false"); + await streamWriter.FlushAsync(); + } + + foreach (var directory in directories) + { + await streamWriter.WriteAsync($" {directory} true"); + await streamWriter.FlushAsync(); + } + } + + /// + /// Method for get files + /// + /// stream + /// path to file + /// + private static async Task Get(NetworkStream stream, string path) + { + using var streamWriter = new StreamWriter(stream); + if (!File.Exists(path)) + { + await streamWriter.WriteAsync("-1"); + await streamWriter.FlushAsync(); + return; + } + var size = (new FileInfo(path)).Length; + await streamWriter.WriteLineAsync(size.ToString()); + await streamWriter.FlushAsync(); + using var fileStream = new FileStream(path, FileMode.Open); + await fileStream.CopyToAsync(streamWriter.BaseStream); + await streamWriter.FlushAsync(); + } + + /// + /// 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) + { + using var acceptedSocket = tcpListener.AcceptSocket(); + using var newtworkStream = new NetworkStream(acceptedSocket); + using var streamReader = new StreamReader(newtworkStream); + var strings = (streamReader.ReadLine())?.Split(' '); + if (strings == null) + { + continue; + } + switch (strings[0]) + { + case "list": + { + await Task.Run(() => List(newtworkStream, strings[1])); + break; + } + case "get": + { + await Task.Run(() => Get(newtworkStream, strings[1])); + break; + } + default: + { + continue; + } + } + } + + 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..7b1513a --- /dev/null +++ b/Server/Server/Server/Solution.cs @@ -0,0 +1,66 @@ +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; +} + +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..193bee5 --- /dev/null +++ b/Server/Server/ServerTest/ServerTest.cs @@ -0,0 +1,66 @@ +namespace ServerTest; + +using System.Net; +using Server; + +public class Tests +{ + Server? server; + CancellationTokenSource? cancelTokenSource; + [SetUp] + public void Setup() + { + server = new Server(IPAddress.Loopback, 80); + var cancelTokenSource = new CancellationTokenSource(); + var serverTask = Task.Run(() => server.Start(cancelTokenSource), cancelTokenSource.Token); + } + + [Test] + public void ShouldExpectedDirectoryNotFoundExceptionIfListForNonExistentDirectory() + { + var client = new Client(IPAddress.Loopback, 80); + Assert.ThrowsAsync(() => client.List("./NonExistentDirectory")); + } + + [Test] + public void ShouldExpectedFileNotFoundExceptionIfGetForNonExistentFile() + { + var client = new Client(IPAddress.Loopback, 80); + Assert.ThrowsAsync(() => client.Get("NonExistentFile.txt")); + } + + [Test] + public async Task ShouldExpectedResultsOfGetAreTheSameForDifferentClients() + { + var client = new Client(IPAddress.Loopback, 80); + var newClient = new Client(IPAddress.Loopback, 80); + var(size, bytes) = await client.Get("..//..//..//Files//azaza.txt"); + var(newSize, newBytes) = await newClient.Get("..//..//..//Files//azaza.txt"); + Assert.Multiple(() => + { + Assert.That(size, Is.EqualTo(newSize)); + Assert.That(bytes, Is.EqualTo(newBytes)); + }); + } + + [Test] + public void ShouldExpectedThatMultipleClientsCanAccessTheFile() + { + var firstClient = new Client(IPAddress.Loopback, 80); + var secondClient = new Client(IPAddress.Loopback, 80); + var thirdClient = new Client(IPAddress.Loopback, 80); + var firstTask = Task.Run(() => firstClient.Get("..//..//..//Files//azaza.txt")); + var secondTask = Task.Run(() => secondClient.Get("..//..//..//Files//azaza.txt")); + var thirdTask = Task.Run(() => secondClient.Get("..//..//..//Files//azaza.txt")); + var (firstSize, firstBytes) = firstTask.Result; + var (secondSize, secondBytes) = secondTask.Result; + var (thirdSize, thirdBytes) = thirdTask.Result; + 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 From 6cf3d700e61f4f1accb1c9b89e5c7ebb6be7dbf8 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 2 Nov 2022 22:58:28 +0300 Subject: [PATCH 2/5] fixed warning --- Server/Server/ServerTest/ServerTest.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Server/Server/ServerTest/ServerTest.cs b/Server/Server/ServerTest/ServerTest.cs index 193bee5..49591b0 100644 --- a/Server/Server/ServerTest/ServerTest.cs +++ b/Server/Server/ServerTest/ServerTest.cs @@ -6,11 +6,11 @@ namespace ServerTest; public class Tests { Server? server; - CancellationTokenSource? cancelTokenSource; + [SetUp] public void Setup() { - server = new Server(IPAddress.Loopback, 80); + server = new Server(IPAddress.Loopback, 10000); var cancelTokenSource = new CancellationTokenSource(); var serverTask = Task.Run(() => server.Start(cancelTokenSource), cancelTokenSource.Token); } @@ -18,22 +18,22 @@ public void Setup() [Test] public void ShouldExpectedDirectoryNotFoundExceptionIfListForNonExistentDirectory() { - var client = new Client(IPAddress.Loopback, 80); + var client = new Client(IPAddress.Loopback, 10000); Assert.ThrowsAsync(() => client.List("./NonExistentDirectory")); } [Test] public void ShouldExpectedFileNotFoundExceptionIfGetForNonExistentFile() { - var client = new Client(IPAddress.Loopback, 80); + var client = new Client(IPAddress.Loopback, 10000); Assert.ThrowsAsync(() => client.Get("NonExistentFile.txt")); } [Test] public async Task ShouldExpectedResultsOfGetAreTheSameForDifferentClients() { - var client = new Client(IPAddress.Loopback, 80); - var newClient = new Client(IPAddress.Loopback, 80); + var client = new Client(IPAddress.Loopback, 10000); + var newClient = new Client(IPAddress.Loopback, 10000); var(size, bytes) = await client.Get("..//..//..//Files//azaza.txt"); var(newSize, newBytes) = await newClient.Get("..//..//..//Files//azaza.txt"); Assert.Multiple(() => @@ -46,9 +46,9 @@ public async Task ShouldExpectedResultsOfGetAreTheSameForDifferentClients() [Test] public void ShouldExpectedThatMultipleClientsCanAccessTheFile() { - var firstClient = new Client(IPAddress.Loopback, 80); - var secondClient = new Client(IPAddress.Loopback, 80); - var thirdClient = new Client(IPAddress.Loopback, 80); + var firstClient = new Client(IPAddress.Loopback, 10000); + var secondClient = new Client(IPAddress.Loopback, 10000); + var thirdClient = new Client(IPAddress.Loopback, 10000); var firstTask = Task.Run(() => firstClient.Get("..//..//..//Files//azaza.txt")); var secondTask = Task.Run(() => secondClient.Get("..//..//..//Files//azaza.txt")); var thirdTask = Task.Run(() => secondClient.Get("..//..//..//Files//azaza.txt")); From 01f7696bd235dfa0fac457b237b14a01aa86e066 Mon Sep 17 00:00:00 2001 From: Roman Date: Wed, 2 Nov 2022 23:09:21 +0300 Subject: [PATCH 3/5] formatted --- Server/Server/Server/Client.cs | 8 +++++++- Server/Server/ServerTest/ServerTest.cs | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Server/Server/Server/Client.cs b/Server/Server/Server/Client.cs index 6bfa543..ec60940 100644 --- a/Server/Server/Server/Client.cs +++ b/Server/Server/Server/Client.cs @@ -42,15 +42,18 @@ public Client(IPAddress adress, int port) { 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++) { @@ -77,18 +80,21 @@ public Client(IPAddress adress, int port) var client = new TcpClient(); await client.ConnectAsync(address, port); using var stream = client.GetStream(); - using var streamWriter = new StreamWriter(stream) { AutoFlush = true }; + using var streamWriter = new StreamWriter(stream); await streamWriter.WriteLineAsync($"get {pathToFile}"); + await streamWriter.FlushAsync(); 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/ServerTest/ServerTest.cs b/Server/Server/ServerTest/ServerTest.cs index 49591b0..e92d116 100644 --- a/Server/Server/ServerTest/ServerTest.cs +++ b/Server/Server/ServerTest/ServerTest.cs @@ -39,7 +39,7 @@ public async Task ShouldExpectedResultsOfGetAreTheSameForDifferentClients() Assert.Multiple(() => { Assert.That(size, Is.EqualTo(newSize)); - Assert.That(bytes, Is.EqualTo(newBytes)); + Assert.That(bytes, Is.EquivalentTo(newBytes)); }); } From 5719a7a4b656433d3ad83065ceb4916d74be23cb Mon Sep 17 00:00:00 2001 From: Roman Date: Mon, 7 Nov 2022 19:28:17 +0300 Subject: [PATCH 4/5] Changing the server operation Changed tests Added comments --- Server/Server/Server/Client.cs | 10 ++++ Server/Server/Server/Server.cs | 63 ++++++++++++++++++-------- Server/Server/Server/Solution.cs | 6 +++ Server/Server/ServerTest/ServerTest.cs | 28 +++--------- 4 files changed, 66 insertions(+), 41 deletions(-) diff --git a/Server/Server/Server/Client.cs b/Server/Server/Server/Client.cs index ec60940..e53dbfc 100644 --- a/Server/Server/Server/Client.cs +++ b/Server/Server/Server/Client.cs @@ -31,12 +31,22 @@ public Client(IPAddress adress, int port) 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); + + // Отправляем сообщение подключенному tcpсерверу. await streamWriter.WriteLineAsync($"list {pathToDiretory}"); await streamWriter.FlushAsync(); using var streamReader = new StreamReader(stream); + + // Получаем ответ от сервера var data = await streamReader.ReadLineAsync(); if (data == null) { diff --git a/Server/Server/Server/Server.cs b/Server/Server/Server/Server.cs index 14bdba3..9832a50 100644 --- a/Server/Server/Server/Server.cs +++ b/Server/Server/Server/Server.cs @@ -35,6 +35,8 @@ private static async Task List(NetworkStream stream, string path) if (!Directory.Exists(path)) { await streamWriter.WriteAsync("-1"); + + // Посылаем ответ клиенту await streamWriter.FlushAsync(); return; } @@ -48,12 +50,16 @@ private static async Task List(NetworkStream stream, string path) foreach (var file in files) { await streamWriter.WriteAsync($" {file} false"); + + // Посылаем ответ клиенту await streamWriter.FlushAsync(); } foreach (var directory in directories) { await streamWriter.WriteAsync($" {directory} true"); + + // Посылаем ответ клиенту await streamWriter.FlushAsync(); } } @@ -70,6 +76,8 @@ private static async Task Get(NetworkStream stream, string path) if (!File.Exists(path)) { await streamWriter.WriteAsync("-1"); + + // Посылаем ответ клиенту await streamWriter.FlushAsync(); return; } @@ -78,6 +86,8 @@ private static async Task Get(NetworkStream stream, string path) await streamWriter.FlushAsync(); using var fileStream = new FileStream(path, FileMode.Open); await fileStream.CopyToAsync(streamWriter.BaseStream); + + // Посылаем ответ клиенту await streamWriter.FlushAsync(); } @@ -88,35 +98,48 @@ private static async Task Get(NetworkStream stream, string path) public async Task Start(CancellationTokenSource source) { var tcpListener = new TcpListener(address, port); + + // Слушаем порт tcpListener.Start(); while (!source.Token.IsCancellationRequested) { - using var acceptedSocket = tcpListener.AcceptSocket(); - using var newtworkStream = new NetworkStream(acceptedSocket); - using var streamReader = new StreamReader(newtworkStream); - var strings = (streamReader.ReadLine())?.Split(' '); - if (strings == null) - { - continue; - } - switch (strings[0]) + // Блокируем поток до установления соединения + var acceptedSocket = await tcpListener.AcceptSocketAsync(); + + // Каждый клиент обслуживается в своем потоке. Т.к. async, то не будет блокировок при чтении больших файлов + await Task.Run(async() => { - case "list": - { - await Task.Run(() => List(newtworkStream, strings[1])); - break; - } - case "get": + // Поток для записи и чтения в полученный сокет + using var newtworkStream = new NetworkStream(acceptedSocket); + + // Получаем сообщение от клиента + using var streamReader = new StreamReader(newtworkStream); + var strings = (streamReader.ReadLine())?.Split(' '); + if (strings == null) { - await Task.Run(() => Get(newtworkStream, strings[1])); - break; + throw new InvalidDataException(); } - default: + + switch (strings[0]) { - continue; + case "list": + { + await List(newtworkStream, strings[1]); + break; + } + case "get": + { + await Get(newtworkStream, strings[1]); + break; + } + default: + { + throw new InvalidDataException(); + } } - } + acceptedSocket.Close(); + }); } tcpListener.Stop(); diff --git a/Server/Server/Server/Solution.cs b/Server/Server/Server/Solution.cs index 7b1513a..5ddf08d 100644 --- a/Server/Server/Server/Solution.cs +++ b/Server/Server/Server/Solution.cs @@ -24,6 +24,12 @@ 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); diff --git a/Server/Server/ServerTest/ServerTest.cs b/Server/Server/ServerTest/ServerTest.cs index e92d116..46f56d2 100644 --- a/Server/Server/ServerTest/ServerTest.cs +++ b/Server/Server/ServerTest/ServerTest.cs @@ -30,31 +30,17 @@ public void ShouldExpectedFileNotFoundExceptionIfGetForNonExistentFile() } [Test] - public async Task ShouldExpectedResultsOfGetAreTheSameForDifferentClients() - { - var client = new Client(IPAddress.Loopback, 10000); - var newClient = new Client(IPAddress.Loopback, 10000); - var(size, bytes) = await client.Get("..//..//..//Files//azaza.txt"); - var(newSize, newBytes) = await newClient.Get("..//..//..//Files//azaza.txt"); - Assert.Multiple(() => - { - Assert.That(size, Is.EqualTo(newSize)); - Assert.That(bytes, Is.EquivalentTo(newBytes)); - }); - } - - [Test] - public void ShouldExpectedThatMultipleClientsCanAccessTheFile() + 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 = Task.Run(() => firstClient.Get("..//..//..//Files//azaza.txt")); - var secondTask = Task.Run(() => secondClient.Get("..//..//..//Files//azaza.txt")); - var thirdTask = Task.Run(() => secondClient.Get("..//..//..//Files//azaza.txt")); - var (firstSize, firstBytes) = firstTask.Result; - var (secondSize, secondBytes) = secondTask.Result; - var (thirdSize, thirdBytes) = thirdTask.Result; + 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)); From df68c00b156bdc5b397560c70a5de864554dcb2b Mon Sep 17 00:00:00 2001 From: Roman Date: Thu, 24 Nov 2022 16:11:36 +0300 Subject: [PATCH 5/5] formatted --- Server/Server/Server/Client.cs | 12 +++------ Server/Server/Server/Server.cs | 46 ++++++++++++---------------------- 2 files changed, 19 insertions(+), 39 deletions(-) diff --git a/Server/Server/Server/Client.cs b/Server/Server/Server/Client.cs index e53dbfc..821e2e1 100644 --- a/Server/Server/Server/Client.cs +++ b/Server/Server/Server/Client.cs @@ -39,11 +39,10 @@ public Client(IPAddress adress, int port) using var stream = client.GetStream(); - using var streamWriter = new StreamWriter(stream); + using var streamWriter = new StreamWriter(stream) { AutoFlush = true }; // Отправляем сообщение подключенному tcpсерверу. await streamWriter.WriteLineAsync($"list {pathToDiretory}"); - await streamWriter.FlushAsync(); using var streamReader = new StreamReader(stream); // Получаем ответ от сервера @@ -67,11 +66,7 @@ public Client(IPAddress adress, int port) var list = new List<(string, bool)>(); for (int i = 1; i < strings.Length; i++) { - bool flag = true; - if (strings[i + 1] == "false") - { - flag = false; - } + bool flag = strings[i + 1] != "false"; list.Add((strings[i], flag)); i++; } @@ -90,9 +85,8 @@ public Client(IPAddress adress, int port) var client = new TcpClient(); await client.ConnectAsync(address, port); using var stream = client.GetStream(); - using var streamWriter = new StreamWriter(stream); + using var streamWriter = new StreamWriter(stream) { AutoFlush = true }; await streamWriter.WriteLineAsync($"get {pathToFile}"); - await streamWriter.FlushAsync(); using var streamReader = new StreamReader(stream); var stringWithSize = (await streamReader.ReadLineAsync()); if (!int.TryParse(stringWithSize, out int size)) diff --git a/Server/Server/Server/Server.cs b/Server/Server/Server/Server.cs index 9832a50..68b4330 100644 --- a/Server/Server/Server/Server.cs +++ b/Server/Server/Server/Server.cs @@ -30,37 +30,28 @@ public Server(IPAddress adress, int port) /// private static async Task List(NetworkStream stream, string path) { - using var streamWriter = new StreamWriter(stream); + using var streamWriter = new StreamWriter(stream) { AutoFlush = true }; if (!Directory.Exists(path)) { await streamWriter.WriteAsync("-1"); - - // Посылаем ответ клиенту - await streamWriter.FlushAsync(); return; } var directories = Directory.GetDirectories(path); var files = Directory.GetFiles(path); var size = directories.Length + files.Length; + await streamWriter.WriteAsync(size.ToString()); - await streamWriter.FlushAsync(); foreach (var file in files) { await streamWriter.WriteAsync($" {file} false"); - - // Посылаем ответ клиенту - await streamWriter.FlushAsync(); } foreach (var directory in directories) { await streamWriter.WriteAsync($" {directory} true"); - - // Посылаем ответ клиенту - await streamWriter.FlushAsync(); } } @@ -72,23 +63,17 @@ private static async Task List(NetworkStream stream, string path) /// private static async Task Get(NetworkStream stream, string path) { - using var streamWriter = new StreamWriter(stream); + using var streamWriter = new StreamWriter(stream) { AutoFlush = true }; if (!File.Exists(path)) { await streamWriter.WriteAsync("-1"); - - // Посылаем ответ клиенту - await streamWriter.FlushAsync(); return; } + var size = (new FileInfo(path)).Length; await streamWriter.WriteLineAsync(size.ToString()); - await streamWriter.FlushAsync(); using var fileStream = new FileStream(path, FileMode.Open); await fileStream.CopyToAsync(streamWriter.BaseStream); - - // Посылаем ответ клиенту - await streamWriter.FlushAsync(); } /// @@ -124,20 +109,21 @@ await Task.Run(async() => switch (strings[0]) { case "list": - { - await List(newtworkStream, strings[1]); - break; - } + { + await List(newtworkStream, strings[1]); + break; + } case "get": - { - await Get(newtworkStream, strings[1]); - break; - } + { + await Get(newtworkStream, strings[1]); + break; + } default: - { - throw new InvalidDataException(); - } + { + throw new InvalidDataException(); + } } + acceptedSocket.Close(); }); }