Skip to content

MyFTP#4

Open
MikePuzanov wants to merge 17 commits intomasterfrom
MyFTP
Open

MyFTP#4
MikePuzanov wants to merge 17 commits intomasterfrom
MyFTP

Conversation

@MikePuzanov
Copy link
Copy Markdown
Owner

No description provided.

Copy link
Copy Markdown
Collaborator

@yurii-litvinov yurii-litvinov left a comment

Choose a reason for hiding this comment

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

Что-то проектные файлы вообще не выложены :) И ConsoleApp1 как имя проекта не годится. И тестов нет.

Comment thread MyFTP/MyFTP/Program.cs Outdated
static void Main(string[] args)
{

}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Не, я хочу две консольные программы --- для сервера и для клиента. Чтобы я мог запустить сервер, и затем запустить клиент и подконнектиться к серверу.

Comment thread MyFTP/ConsoleApp1/Client.cs Outdated

namespace ConsoleApp1
{
public class Client
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Нужны комментарии

Comment thread MyFTP/ConsoleApp1/Client.cs Outdated

public async Task<(string name, bool isDir)[]> List(string path)
{
using var client = new TcpClient(_host, _port);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Не-а, это заставит TcpClient синхронно подключаться к хосту, так что если у него не выйдет, процесс затянется до наступления таймаута, а всё это время поток будет висеть. Надо ConnectAsync

Comment thread MyFTP/ConsoleApp1/Client.cs Outdated

for (int i = 0; i < size; i++)
{
var name = await reader.ReadLineAsync();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

По протоколу разделители --- пробелы, поэтому сервер вообще не может папки с пробелами правильно обрабатывать. Но протокол есть протокол, от него нельзя отступать, потому что Вы решили, что так правильнее.

Comment thread MyFTP/ConsoleApp1/Client.cs Outdated
throw new FileNotFoundException();
}

var content = new byte[size];
Copy link
Copy Markdown
Collaborator

@yurii-litvinov yurii-litvinov Nov 6, 2021

Choose a reason for hiding this comment

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

Не надо грузить файл в память целиком, файлы могут быть очень большие. stream.CopyToAsync вполне ок.

Comment thread MyFTP/MyFTP/Client.cs Outdated
/// <summary>
/// запрос на листинг файлов в папке по пути
/// </summary>
public async Task<(string name, bool isDir)[]> List(string path)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Кстати, все длительные операции должны быть прерываемы, так что и List, и Get должны принимать CancellationToken

Comment thread MyFTP/MyFTP/Server.cs Outdated
while (!_cancellationToken.IsCancellationRequested)
{
var client = await _listener.AcceptTcpClientAsync();
Working(client);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Многопоточность не поддержана, пока обслуживают одного клиента, второй не может подключиться. А надо

Comment thread MyFTP/MyFTP/Server.cs Outdated
Comment on lines +52 to +54
var stream = client.GetStream();
var reader = new StreamReader(stream);
var writer = new StreamWriter(stream);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Они все IDisposable, так что должны быть using. client тоже, кстати

Comment thread MyFTP/MyFTP/Server.cs Outdated
await Get(writer, path, stream);
break;
default:
throw new ArgumentException();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Так сервер упадёт, а клиент об этом ничего не узнает. Надо исключение бросать не сюда, а сообщать клиенту по сети, что ошибка протокола.

Comment thread MyFTP/MyFTP/Server.cs Outdated
{
await writer.WriteLineAsync("-1");
await writer.FlushAsync();
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

И дальше продолжили работать как ни в чём не бывало :)

Comment thread MyFTP/MyFTPClient/MyFTPClient.csproj Outdated

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Можно уже на .net 6 и C# 10 переходить, там всякие крутые штуки типа file-scoped namespaces и глобальных юзингов.

Comment thread MyFTP/MyFTPServer/Dockerfile Outdated
@@ -0,0 +1,18 @@
FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

👍

Comment thread MyFTP/MyFTP.Test/MyFTPTest.cs Outdated
Comment on lines +21 to +22
_server = new Server("127.0.0.1", 80);
_client = new Client(80, "127.0.0.1");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Как-то оно хаотично, у одного сначала IP, потом порт, у второго наоборот

Comment thread MyFTP/MyFTP.Test/MyFTPTest.cs Outdated
public void GetInvalidFileNameTest()
{
Assert.Throws<AggregateException>(() => _client.Get("Text.txt", _fileStream, _cancellationToken).Wait());
_server.StopServer();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Это стоит в TearDown написать, а то если вдруг тест не пройдёт и минует StopServer, остальные тесты, скорее всего, даже не запустятся, потому что порт занят.

Comment thread MyFTP/MyFTP.Test/MyFTPTest.cs Outdated
[Test]
public async Task ListInvalidFileNameTest()
{
Assert.Throws<AggregateException>(() => _client.Get("Text.txt", _fileStream, _cancellationToken).Wait());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Бывает Assert.ThrowsAsync

Comment thread MyFTP/MyFTPServer/Program.cs Outdated
Console.WriteLine("Введите IP сервер:");
var ipAddress = Console.ReadLine();
Console.WriteLine("Введите порт сервера:");
var port = int.Parse(Console.ReadLine());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Тут тем более. Сервер в принципе не предполагает какой-то интерактивности, поэтому только аргументы командной строки, никаких ReadLine-ов :)

Comment thread MyFTP/MyFTPServer/Program.cs Outdated
command = Console.ReadLine();
}
}
catch (Exception e)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
catch (Exception e)
catch (Exception)

Comment thread MyFTP/MyFTPServer/Server.cs Outdated
public class Server
{
private readonly TcpListener _listener;
private readonly CancellationTokenSource _cancellationToken = new ();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Так это Source или токен? Мне кажется, Вы путаете фабрику и продукт. См. https://stackoverflow.com/questions/14215784/why-cancellationtoken-is-separate-from-cancellationtokensource

Comment thread MyFTP/MyFTPServer/Server.cs Outdated
while (!_cancellationToken.IsCancellationRequested)
{
var client = await _listener.AcceptTcpClientAsync();
Working(client);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Working нигде не await-ится, что огорчает компилятор и даёт возможность остановить сервер до того, как он успел ответить клиенту, что может привести к порче данных. Тут можно было сложить таск, который вернёт Working, в список, и потом в конце заawait-ить их все.

Comment thread MyFTP/MyFTPServer/Server.cs Outdated
foreach (var dir in directories)
{
result += $" {dir} true";
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Конкатенировать строки в цикле правильнее StringBuilder-ом. Без него это одна большая утечка памяти, квадратичная от размера строки.

using System.Threading.Tasks;
using NUnit.Framework;

public class Tests

This comment was marked as resolved.

This comment was marked as resolved.

Comment thread MyFTP/MyFTP.Test/MyFTPTest.cs Outdated
[Test]
public void GetInvalidFileNameTest()
{
Assert.ThrowsAsync<AggregateException>(() => Task.Run(() => _client.Get("Text.txt", _fileStream, _cancellationToken).Wait()));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Task.Run(...).Wait() --- это практически то же самое, что просто ..., эта конструкция довольно бессмысленна. На что намекает в частности то, что тут лямбда не асинхронная.

Assert.AreEqual(result, result2);
File.Delete(destination);
}
} No newline at end of file

This comment was marked as resolved.

/// <summary>
/// класс клиента для общения с сервером
/// </summary>
public class Client

This comment was marked as resolved.

Comment thread MyFTP/MyFTPClient/Client.cs Outdated
var size = Convert.ToInt32(infoArray[0]);
if (size == -1)
{
throw new Exception();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ой, нет, кидать Exception запрещено :) Это слишком общее исключение

Comment thread MyFTP/MyFTPClient/Client.cs Outdated
}
if (size == -1)
{
throw new ArgumentException();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Это тоже. ArgumentException --- это когда нам неверные параметры передали

Comment thread MyFTP/MyFTPClient/Program.cs Outdated
global using System.IO;

var client = new Client(args[0], Convert.ToInt32(args[1]));
var request = Console.ReadLine().Split(' ');
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Передавать аргументы в консольное приложение не через args, а с помощью ReadLine --- нельзя, замучаетесь скрипты писать

Comment thread MyFTP/MyFTPClient/Program.cs Outdated

if (request[0] == "2")
{
using (var fstream = new FileStream(request[2], FileMode.OpenOrCreate))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Тут лучше просто using var, отдельный scope тут не нужен

Comment thread MyFTP/MyFTPClient/Program.cs Outdated
Console.WriteLine($"{file.Item1} {file.Item2}");
}
}
catch (Exception)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ловить просто Exception тоже нельзя, кстати

Comment thread MyFTP/MyFTPServer/Program.cs Outdated
try
{
var server = new Server(args[0], Convert.ToInt32(args[1]));
await server.StartServer();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Есть ли какой-нибудь способ его остановить? :)

using System.Threading.Tasks;
using NUnit.Framework;

public class Tests

This comment was marked as resolved.

Comment thread MyFTP/MyFTP.Test/MyFTPTest.cs Outdated
_client = new Client("127.0.0.1", 80);
_fileStream = new MemoryStream();
_cancellationToken = new ();
_= _server.StartServer();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Зачем присваивание в никуда? :) И пробела не хватает

Comment thread MyFTP/MyFTPClient/Program.cs Outdated
{
var client = new Client(args[0], Convert.ToInt32(args[1]));
var token = new CancellationToken();
while (args[0] != "exit" || !token.IsCancellationRequested)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

args[0] != "exit" выглядит довольно странно. Будто args[0] как-то может поменяться :)

Comment thread MyFTP/MyFTPClient/Program.cs Outdated

if (args[0] == "2")
{
using (var fstream = new FileStream(args[2], FileMode.OpenOrCreate))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Можно using var без скобок

{
var server = new Server(args[0], Convert.ToInt32(args[1]));
await server.StartServer();
Console.WriteLine("Введите !exit, чтобы остановить сервер");

This comment was marked as resolved.

{
try
{
var server = new Server(args[0], Convert.ToInt32(args[1]));

This comment was marked as resolved.

while (command != "!exit")
{
command = Console.ReadLine();
}

This comment was marked as resolved.

Comment thread MyFTP/MyFTPServer/Server.cs Outdated
/// </summary>
private async Task Working(TcpClient client)
{
using var stream = client.GetStream();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

client реализует IDisposable, так что надо сначала using на него сделать

Copy link
Copy Markdown
Collaborator

@yurii-litvinov yurii-litvinov left a comment

Choose a reason for hiding this comment

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

Да, вот теперь всё правильно, хоть и неаккуратно. Зачтена.

[Test]
public void ParallelClientConnection()
{
var clients = new Task[2];
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ну, два клиента — это не очень убедительно, было бы их хотя бы 200... Но ладно.

Comment on lines +44 to +48
var data = new List<(string, bool)>();



for (int i = 1; i < infoArray.Length; i += 2)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
var data = new List<(string, bool)>();
for (int i = 1; i < infoArray.Length; i += 2)
var data = new List<(string, bool)>();
for (int i = 1; i < infoArray.Length; i += 2)

Comment on lines +49 to +51
{

var isDir = Convert.ToBoolean(infoArray[i + 1]);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
{
var isDir = Convert.ToBoolean(infoArray[i + 1]);
{
var isDir = Convert.ToBoolean(infoArray[i + 1]);

var token = new CancellationToken();
Console.WriteLine("1 - List — листинг файлов в директории на сервере\nНапример, 1 ./Test/Files\n");
Console.WriteLine("2 - Get — скачивание файла с сервера\n2 ./Test/Files/file1.txt\n");
Console.WriteLine("Введите !exit, чтобы остановить сервер\n");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Мы клиент, зачем останавливать сервер

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants