rust - 如何在数据结构中存储带有 BufReader 和 BufWriter 的 TcpStream

标签 rust

我想要一个 TcpStream由一个 BufReader 共享和一个 BufWriter ,我在以下地方找到了解决方案:
If BufReader takes ownership of a stream, how can I read and write lines on it?

现在我想要它在它自己的数据结构中,但我只得到了部分答案:
Why can't I store a value and a reference to that value in the same struct?

所需的实现违反了所有权规则。

use std::io::{BufReader, BufWriter};
use std::net::TcpStream;

pub struct BufTcpStream<'a> {
    _socket: TcpStream,
    input:  BufReader<&'a TcpStream>;
    output: BufWriter<&'a TcpStream>;
}

impl<'a> BufTcpStream<'a> {
    pub fn new(socket: TcpStream) -> Self {
        Self{
            input : BufReader::new(&socket),
            output: BufWriter::new(&socket),
            _socket: socket,//                 <-- MOVE OF BORROWED VALUE HERE
        }
    }
}

为了解决这个问题,我必须确保 TcpStream引用将在整个结构生命周期内保持有效,我使用了 Pin<Box<TcpStream>>以确保它。

但编译器仍然提示借用值的移动socket .为了消除这个障碍,我使用了 std::meme::transmute() .

现在,我想知道的是:

这个实现安全吗?

use std::io::{BufReader, BufWriter};
use std::net::TcpStream;
use std::pin::Pin;

pub struct BufTcpStream<'a> {
    _socket: Pin<Box<TcpStream>>,
    input : BufReader<&'a TcpStream>,
    output: BufWriter<&'a TcpStream>,
}

impl<'a> BufTcpStream<'a> {
    pub fn new(socket: TcpStream) -> Self {
        let pin = Box::pin(socket);
        unsafe {
            Self{
                input : BufReader::new(std::mem::transmute(&*pin)),
                output: BufWriter::new(std::mem::transmute(&*pin)),
                _socket: pin,
            }
        }
    }
    pub fn reach(&mut self) -> (
        &mut BufReader<&'a TcpStream>,
        &mut BufWriter<&'a TcpStream>
    ) {
        (&mut self.input, &mut self.output)
    }
}

最佳答案

使用TcpStream::try_clone获得第二个流:

The returned TcpStream is a reference to the same stream that this object references. Both handles will read and write the same stream of data, and options set on one stream will be propagated to the other stream.

然后您可以将一个包装在 reader 中,将一个包装在 writer 中:

use std::{
    io::{self, BufReader, BufWriter},
    net::TcpStream,
};

struct BufTcpStream {
    input: BufReader<TcpStream>,
    output: BufWriter<TcpStream>,
}

impl BufTcpStream {
    fn new(stream: TcpStream) -> io::Result<Self> {
        let input = BufReader::new(stream.try_clone()?);
        let output = BufWriter::new(stream);

        Ok(Self { input, output })
    }
}

另见:

关于rust - 如何在数据结构中存储带有 BufReader 和 BufWriter 的 TcpStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58467659/

相关文章:

rust - 如何链接到 rustdoc 中的其他 fns/structs/enums/traits?

io - 如果无法查找标准输入,我如何从标准输入或文件获取输入?

performance - 尝试着名的分支预测示例有时会导致奇怪的时间

rust - 是否可以在函数参数中将切片/向量强制转换为 'Cow<[type]>' ?

rust - 为什么在迭代期间需要 `&` 来解构元组列表?

rust - 如何创建一个全局的、可变的单例?

websocket - 在同一端口上运行 websocket 和 http 服务器(Rust、hyper)

rust - 表达式中是否有类型注释的语法? (示例用例 : Default trait)

rust - 如何概括使用不同类型的键传递给函数的HashMap?

type-conversion - From 和 Into 特征以及 usize 到 f64 的转换