如何使用BufReader和BufWriter在数据结构中存储TcpStream

问题描述 投票:2回答:1

编辑:请停止将此帖子重复报告,如果您只阅读了前两行,您将了解它不是重复的。

  • 我想要TcpStreamBufReader共享一个BufWriter,我得到了解决方案there
  • 现在,我想要它自己的数据结构,我只有一个部分答案there

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

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

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

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

但是编译器仍然抱怨借入值socket的移动。为了消除此障碍,我使用了transmute

现在,我想知道的是:

此实施安全吗?

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

impl<'a> BufferedTcpStream<'a> {
    pub fn new(socket: TcpStream) -> BufferedTcpStream<'a> {
        let pin = Box::pin(socket);
        unsafe {
            BufferedTcpStream{
                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)
    }
}
rust
1个回答
0
投票

没有此实现不安全。

TcpStream的引用可以比结构本身更长寿:

let bad_ref = {
    let buffer = BufferedTcpStream(TcpStream::connect("[::1]:4321").unwrap());
    let (i, o) = buffer.reach();
    *i.get_ref()
};
// bad_ref is now an invalid ref but the compiler won't see it

*i.get_ref()的类型为&'a TcpStream,但是&'a的生存期永远不会由编译器推断出来,因此不会考虑在内。

可以通过将reach()的生存期链接到返回的引用,将其固定在self方法中:

fn reach<'b>(&'b mut self) -> (
    &mut BufReader<&'b TcpStream>,
    &mut BufWriter<&'b TcpStream>
) {
    (&mut self.input, &mut self.output)
}

实际上,'a中的struct BufferedTcpStream<'a>生存期是无用的。可以将不安全引用的生存期设置为'static

这里是固定的实现:

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

impl BufferedTcpStream {
    pub fn new(socket: TcpStream) -> BufferedTcpStream {
        let pin = Box::pin(socket);
        unsafe {
            BufferedTcpStream{
                input : BufReader::new(std::mem::transmute(&*pin)),
                output: BufWriter::new(std::mem::transmute(&*pin)),
                _socket: pin,
            }
        }
    }
    pub fn reach<'b>(&'b mut self) -> (
        &mut BufReader<&'b TcpStream>,
        &mut BufWriter<&'b TcpStream>
    ) {
        unsafe {
            std::mem::transmute((&mut self.input, &mut self.output))
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.