首页 文章

为什么Arc :: try_unwrap()导致恐慌?

提问于
浏览
1

我正在写一个简单的聊天服务器,它向所有连接的客户端广播消息 .

代码可能看起来很糟糕,因为我是初学者 . 对等体还没有在任何地方使用,因为我也希望将它传递给 handle_client 函数,所以当数据在流中可用并成功读取时,我想在所有连接的客户端上广播它 . 我知道这不是一个好方法,我只是想了解我怎样才能做到这样的事情 .

use std::io::BufRead;
use std::io::Write;
use std::net::{TcpListener, TcpStream};
use std::sync::Arc;

fn handle_client(arc: Arc<TcpStream>) -> std::io::Result<()> {
    let mut stream = Arc::try_unwrap(arc).unwrap();

    stream.write(b"Welcome to the server!\r\n")?;
    println!("incomming connection: {:?}", stream);

    std::thread::spawn(move || -> std::io::Result<()> {
        let peer_addr = stream.peer_addr()?;
        let mut reader = std::io::BufReader::new(stream);
        let mut buf = String::new();

        loop {
            let bytes_read = reader.read_line(&mut buf)?;
            if bytes_read == 0 {
                println!("client disconnected {}", peer_addr);
                return Ok(());
            }

            buf.remove(bytes_read - 1);
            println!("{}: {}", peer_addr, buf);

            buf.clear();
        }
    });

    Ok(())
}

fn start() -> std::io::Result<()> {
    let listener = TcpListener::bind("0.0.0.0:1111")?;
    println!("listening on {}", listener.local_addr()?.port());

    let mut peers: Vec<Arc<TcpStream>> = vec![];

    for stream in listener.incoming() {
        let mut stream = stream.unwrap();
        let arc = Arc::new(stream);

        peers.push(arc.clone());
        handle_client(arc.clone()).unwrap();
    }

    Ok(())
}

fn main() -> std::io::Result<()> {
    start()
}

它编译得很好,但是在 handle_client 函数恐慌中 let mut stream = Arc::try_unwrap(arc).unwrap(); . 我究竟做错了什么?为什么恐慌?

2 回答

  • 1

    为什么恐慌?

    你在 Result::Err 上调用 unwrap . Err 来自 try_unwrap Arc 失败 .

    我做错了什么?

    展开 Arc 将移动其值并获得它的所有权 . 这失败了,因为有三个相同的 Arc 克隆:

    • 主循环中的一个仍然在范围内
      peers 向量中

    • 一个

    • 你试图打开 handle_client 内的那个 .

    如果Rust允许您解包并移动值,则另外两个克隆将变为无效 . 您可以使用 ArcDeref 实现借用它而不是展开值:

    let stream: &TcpStream = &arc;
    

    由于您现在正在借用 Arc 中的值,您需要在新线程中移动 arc 变量的范围,否则借用检查器将无法确保它与线程一样长寿:

    fn handle_client(arc: Arc<TcpStream>) -> std::io::Result<()> {
        std::thread::spawn(move || -> std::io::Result<()> {
            let mut stream: &TcpStream = &arc;
            stream.write(b"Welcome to the server!\r\n")?;
    
            let peer_addr = stream.peer_addr()?;
            let mut reader = std::io::BufReader::new(stream);
            let mut buf = String::new();
    
            // ... 
         }
    }
    
  • 3

    它在the documentation中说

    如果Arc只有一个强引用,则返回包含的值 . 否则,将返回一个与传入的相同Arc的Err . 即使存在未完成的弱引用,也会成功 .

    weak reference

    你的代码可以很好地使用一个强大的和很多弱引用 .

    let mut peers: Vec<Weak<TcpStream>> = vec![];
    
    for stream in listener.incoming() {
        let mut stream = stream.unwrap();
        let arc = Arc::new(stream);
        peers.push(Arc::downgrade(&arc));
        handle_client(arc).unwrap();
    }
    

    有关弱引用的一点需要注意:如果您打开一个强引用,则无法使用弱引用 .

相关问题