将其包装在BufReader中后,无法从底层读取器读取数据

时间:2018-01-05 22:53:21

标签: sockets networking tcp rust

我的目的是访问TcpStream并在两个不同的结构方法中执行两次读取操作,该方法将TcpStream作为属性。

第一个操作执行正常,但是当我尝试在第二个方法上加载剩余的字节时,无法填充缓冲区。

我试图创造一个非常简单的娱乐。这是它的工作原理:

  1. 某些数据被发送到套接字(8个字节)
  2. 使用read和1字节大小的缓冲区读取1个字节。一切都很好。
  3. 使用read_exact和1字节大小的缓冲区读取1个字节。一切都很好。
  4. 应使用read_exact对基础read对象(stream对象)读取 1字节。缓冲区无法填充。如果我解包,或者带有初始值的缓冲区,我会收到错误。
  5. #[cfg(test)]
    mod tests {
        use std::net::{TcpListener, TcpStream};
        use std::io::{BufReader, Read, Write};
    
        #[test]
        fn test_read_twice() {
            let listener = TcpListener::bind("127.0.0.1:0").unwrap();
            let local_addr = listener.local_addr().unwrap();
            let mut stream = TcpStream::connect(local_addr).unwrap();
            match listener.accept() {
                Ok((mut socket, _)) => {
                    let _ = socket.write_all(&[0, 1, 2, 4, 5, 7]);
                }
                Err(e) => println!("couldn't get client: {:?}", e),
            }
            {
                let mut reader = BufReader::new(&mut stream);
                let mut buff = vec![0u8; 1];
                let _ = reader.read(&mut buff[..]).unwrap();
                assert_eq!(buff, vec![0]);
                let mut buff = vec![0u8; 1];
                let _ = reader.read_exact(&mut buff[..]).unwrap();
                assert_eq!(buff, vec![1]);
            }
            let mut buff = vec![88u8; 1];
            let _ = stream.read_exact(&mut buff[..]);
            assert_eq!(buff, vec![2]);
        }
    }
    

    gist

1 个答案:

答案 0 :(得分:3)

BufReader的意思是“提前” - 您只进行了小读取,但BufReader从底层读取器读取一个大块,将其存储在缓冲区中,并提供服务来自read的请求。此缓冲区归BufReader所有 - 当您在底层阅读器上调用read(或read_exact)时,您无法从该缓冲区中读取。

由于BufReader接口没有公开内部缓冲区,因此以后再次使用底层读取器通常没有意义(您无法可靠地进入缓冲区为空的状态)。因此,不要将引用传递给BufReader::new,而只需按值传递它。通过这种方式,您可以将其永久保留在那里,并在必要时仍然移动BufReader / TcpStream

如果您需要调用其他(不是Read相关的)功能(甚至可以通过{{3}取回),您仍然可以通过get_refget_mut访问基础阅读器},但你会丢失缓冲数据。)