TcpStream上的std :: io :: BufReader会导致数据丢失吗?

时间:2019-10-17 18:57:09

标签: linux networking tcp rust rust-tokio

BufReader用于std::io::BufReader给定(字节)定界符时,tokio::net::TcpStream上的read_until的单个实例会导致数据丢失吗?

也就是说,在我将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的数据,从而导致数据丢失?


我有一个问题(和complete reproducible example on Linux)无法解释上述假设是否正确。

我有一个TCP服务器,该服务器应该在多个并发请求之后将文件的内容发送到多个TCP客户端。

有时,使用始终相同的输入,客户端接收的数据少于预期,因此传输失败。

该错误不会100%地出现(也就是说,某些客户端请求仍然成功),但是在tcp_client.rs中定义了100次尝试后,至少其中之一总是可重复的。 / p>

客户端和服务器之间传输的数据顺序由以下组成:

  1. 客户发送请求
  2. 服务器读取请求并发送响应
  3. 客户阅读了回复
  4. 服务器发送文件数据
  5. 客户端读取文件数据

仅当涉及步骤1、2和3时,此问题才可重现,否则它将按预期工作。

当此tokio::io::read(用于读取文件内容)返回0时,将引发错误,就好像服务器已关闭连接,即使服务器实际上已启动并正在运行,并且所有数据都已发送(在tokio::io::copy之后有一个断言,我使用数据包嗅探器检查了TCP数据包)。顺便说一句,在我的所有运行中,错误发生前读取的数据量始终大于预期的95%。

最重要的是common.rs模块定义了2个不同的read_*函数:

2的逻辑相同,他们需要读取请求/响应(并且客户端和服务器都可以更新为使用一个或另一个)。令人惊讶的是,仅当使用tokio::io::read_untiltokio::io::read_exact正常工作时,该错误才会出现。

除非我滥用tokio::io::read_until或实现中存在错误,否则我希望两个版本都能正常工作。相反,我看到的是this panic的出现,因为某些客户端无法读取服务器发送的所有数据。

1 个答案:

答案 0 :(得分:2)

是的。 documentation for BufReader(重点是我的)中对此进行了描述:

  

放下BufReader时,其缓冲区的内容将被丢弃

下一个句子是正确,但不够广泛:

  

在同一流上创建BufReader的多个实例会导致数据丢失。

BufReader已从基础源读取数据并将其放入缓冲区,然后您就丢弃了缓冲区。数据不见了。