Skip to content

+клиент, +сервер - #23

Open
Palezehvat wants to merge 7 commits into
masterfrom
NewFTPServer
Open

Palezehvat wants to merge 7 commits into
masterfrom
NewFTPServer

Conversation

@Palezehvat

Copy link
Copy Markdown
Owner

No description provided.

Comment thread NewFTPServer/FTPServer/Server.cs Outdated
{
while (!_cancellationToken.IsCancellationRequested)
{
var client = await _listener.AcceptTcpClientAsync();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Здесь нужно и в AcceptTcpClientAsync передавать cancellationToken, иначе listener никогда непозволит серверу остановиться, если к серверу никто не подключиться

Comment thread NewFTPServer/FTPServer/Server.cs Outdated
private static TcpListener? _listener;
private static List<TcpClient>? _clients;
private static CancellationTokenSource? _cancellationToken;
private static List<Task>? _tasks;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Зачем подчеркивания? :)
В Питоне, например, модификаторов видимости нет и это обосновано.
Здесь с маленькой буквы -- поле, с большой - свойство

Comment thread NewFTPServer/FTPServer/Server.cs Outdated

if (!_cancellationToken.IsCancellationRequested)
{
var sizeCommand = await stream.ReadAsync(buffer, 0, buffer.Length);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Лучше сразу читать по строке, чтобы следовать протоколу (команды разделяются символом перевода строки) и не убирать потом \n

Comment thread NewFTPServer/FTPServer/Server.cs Outdated
var command = new StringBuilder();
command.Append(Encoding.UTF8.GetString(buffer, 0, sizeCommand));

var stringCommand = command.ToString();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Зачем здесь StringBuilder? Можно все то же самое без него сделать включая получение первого символа строки

Comment thread NewFTPServer/FTPServer/Server.cs Outdated
foreach (var client in _clients)
{
client.Dispose();
client.Close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Соединения лучше сразу закрывать после того, как сервер ответил. Иначе остаются бесполезные открытые соединения, в которые никто не пишет и из которых никто не читает

Comment thread NewFTPServer/TestsFTP/TestsFTP.cs Outdated
return;
}

var serverThread = new Thread(async () => await server.Start());

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Не, это низкоуровневая многопоточность. В обычной жизни (когда не надо писать тредпул) лучше использовать более высокоуровневые Task-и.
Здесь, например, Task.Run.
И надо останавливать сервер в конце теста, если он такой метод (stop) предоставляет

Comment thread NewFTPServer/FTPClient/Client.cs Outdated
throw new ArgumentNullException();
}

var client = new TcpClient(_hostname, _port);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Не, это инициирует синхронное подключение. Тут надо использовать конструктор без параметров и далее ConnectToAsync

Comment thread NewFTPServer/FTPClient/Client.cs Outdated

var stream = client.GetStream();

await stream.WriteAsync(Encoding.UTF8.GetBytes("2 " + filePath + "\n"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
await stream.WriteAsync(Encoding.UTF8.GetBytes("2 " + filePath + "\n"));
await stream.WriteAsync(Encoding.UTF8.GetBytes($"2 {filePath}\n"));

}

private static async Task<string> GetResultFromStream(NetworkStream stream, string method)
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Зачем передавать method, если он никак не используется? :)
И здесь некоторое неследование протоколу: считывать ответ надо до символа конца строки в случае list-запроса; считывать сначала длину ответа, а потом ответ, используя эту длину, для get-запроса.

Comment thread NewFTPServer/FTPClient/Client.cs Outdated
/// <param name="filePath">The relative path of the file from the specified path on the server</param>
public async Task<string> Get(string filePath)
{
if (_hostname == null)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Кстати, в случае Get запроса лучше передавать от вызывающего поток и туда считывать содержимое файла, полученное от сервера. Либо с помощью CopyToAsync, либо с помощью небольшого промежуточного буффера.

Чтобы файл сразу в память не читать, так как он большой может быть. Пусть вызывающий решает, что с ним делать

Task.WaitAll(tasks.ToArray());
foreach (var client in clients)
{
client.Close();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

"Соединения лучше сразу закрывать после того, как сервер ответил" -- не исправлено

Comment thread NewFTPServer/FTPServer/Server.cs Outdated
var textBytes = File.ReadAllBytes(path);
string text = Encoding.UTF8.GetString(textBytes);
string newText = $"{textBytes.Length} {text}";
await stream.WriteAsync(Encoding.UTF8.GetBytes(newText));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Не, стало только хуже :)
Чтобы не совершать пребразование байты -> строка -> байты, можно сначала отправить длину сообщения (с помощью отдельного WriteAsync), потом текст (с помощью отдельного WriteAsync), а потом сделать Flush

Comment on lines +3 to +5
class Program
{
static async Task Main()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Это не нужно

{
var buffer = new byte[4096];

var sizeResult = await stream.ReadAsync(buffer, 0, buffer.Length);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Уже лучше, но здесь всё-таки надо сначала считывать длину ответа (до пробела), а потом ответ, используя эту длину

/// </summary>
/// <param name="filePath">The relative path of the file from the specified path on the server</param>
public async Task<string> Get(string filePath)
{

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Замечание про запись в поток актуально :)

[TearDown]
public void Teardown()
{
server.Stop();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Тесты падают. Похоже потому что server.Stop() единожды запрашивает остановку, и больше в силу реализации этот сервер уже запуститься не может
Одно из решений: запускать для каждого теста свой сервер на своем порту

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