我正在写一个简单的聊天服务器,它向所有连接的客户端广播消息 .
代码可能看起来很糟糕,因为我是初学者 . 对等体还没有在任何地方使用,因为我也希望将它传递给 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 回答
你在
Result::Err
上调用unwrap
.Err
来自try_unwrap
Arc
失败 .展开
Arc
将移动其值并获得它的所有权 . 这失败了,因为有三个相同的Arc
克隆:主循环中的一个仍然在范围内
在
peers
向量中一个
你试图打开
handle_client
内的那个 .如果Rust允许您解包并移动值,则另外两个克隆将变为无效 . 您可以使用
Arc
的Deref
实现借用它而不是展开值:由于您现在正在借用
Arc
中的值,您需要在新线程中移动arc
变量的范围,否则借用检查器将无法确保它与线程一样长寿:它在the documentation中说
(weak reference)
你的代码可以很好地使用一个强大的和很多弱引用 .
有关弱引用的一点需要注意:如果您打开一个强引用,则无法使用弱引用 .