首页 > 解决方案 > TcpStream 上的 std::io::BufReader 会导致数据丢失吗?

问题描述

当用于给定(字节)分隔符时,单个实例是否std::io::BufReadertokio::net::TcpStream导致数据丢失?BufReaderread_until

也就是说,在我使用BufReaderfor之后有没有可能:

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 时,此问题才可重现,否则按预期工作。

当this tokio::io::read(用于读取文件内容)返回0时报错,好像服务器关闭了连接,甚至服务器实际上已经启动并运行,并且所有数据都已发送(之后有一个断言tokio::io::copy,我使用数据包嗅探器检查 TCP 数据包)。附带说明一下,在我的所有运行中,错误前读取的数据量总是比预期的多 95%。

最重要的是,该common.rs模块定义了 2 个不同的read_*功能:

2 的逻辑是相同的,它们需要读取请求/响应(并且客户端和服务器都可以更新为使用其中一个)。令人惊讶的是,该错误仅在tokio::io::read_until使用时才出现,而tokio::io::read_exact按预期工作。

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

标签: linuxnetworkingtcprustrust-tokio

解决方案


是的。这在(强调我的)的文档中有所描述:BufReader

BufReader被删除时,其缓冲区的内容将被丢弃

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

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

BufReader已从底层源读取数据并将其放入缓冲区,然后您已丢弃缓冲区。数据没了。


推荐阅读