Может ли std :: io :: BufReader на TcpStream привести к потере данных? - PullRequest
1 голос
/ 17 октября 2019

Может ли один экземпляр std::io::BufReader на tokio::net::TcpStream привести к потере данных, когда BufReader используется для read_until aзаданный (байтовый) разделитель?

То есть есть ли вероятность, что после того, как я использую BufReader для:

let buffer = Vec::new();
let reader = BufReader::new(tcp_stream);
tokio::io::read_until(reader, delimiter, buffer)
   .map(move |(s, _)| s.into_inner())

, последующее tokio::io::read с использованием того же потока вернет данныечто на самом деле выходит за разделитель + 1, вызывая, таким образом, потерю данных?


У меня есть проблема (и полный воспроизводимый пример в Linux ), которую я не могу объяснить, если приведенное выше предположениене правильно

У меня есть сервер TCP, который должен отправлять содержимое файла нескольким клиентам TCP после нескольких одновременных запросов.

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

Ошибка не возникает в 100% случаев (то есть некоторые запросы клиентов все еще выполняются), но при 100 попытках, определенных в tcp_client.rs, этовсегда можно было воспроизвести хотя бы для одного из них.

Последовательность данных, передаваемых между клиентом и сервером, состоит из:

  1. , клиент отправляет запрос
  2. сервер прочитал запрос и отправил ответ
  3. клиент прочитал ответ
  4. сервер отправил файл данных
  5. клиент прочитал файл данных

Эта проблема воспроизводима только в том случае, если задействованы шаги 1, 2 и 3, в противном случае она работает как положено.

Ошибка возникает, когда это tokio::io::read (используется для чтениясодержимое файла) возвращает 0, как если бы сервер закрыл соединение, даже если сервер действительно запущен и работает, и все данные были отправлены (после tokio::io::copy есть подтверждение, и я проверилпакеты TCP, использующие анализатор пакетов). Кстати, во всех моих прогонах количество данных, прочитанных до ошибки, всегда было> 95%, чем ожидалось.

Самое главное, модуль common.rs определяет 2 различные функции read_*:

  • read_until используется в настоящее время.
  • read_exact не используется.

Логика2 - то же самое, они должны прочитать запрос / ответ (и клиент и сервер могут быть обновлены, чтобы использовать один или другой). Что удивительно, так это то, что ошибка появляется только при использовании tokio::io::read_until, тогда как tokio::io::read_exact работает, как и ожидалось.

Если только я не использовал tokio::io::read_until или в моей реализации есть ошибка, я ожидал, что обаверсии для работы без каких-либо проблем. Вместо этого я вижу эту панику , вызванную тем, что некоторые клиенты не могут прочитать все данные, отправленные сервером.

1 Ответ

2 голосов
/ 17 октября 2019

Да. Это описано в документации для BufReader (выделено мной):

Когда BufReader отброшено, содержимое его буфера будет отброшено .

Следующее предложение правильное , но недостаточно обширное:

Создание нескольких экземпляров BufReader в одном потоке можетвызвать потерю данных.

BufReader считал данные из базового источника и поместил их в буфер, затем вы выбросили буфер. Данные пропали.

...