В этом коде немало проблем, требующих незначительных исправлений.
Первое, с чем я столкнулся, было использование self в закрытии thread::spawn
. Для потока :: spawn необходимо, чтобы его аргумент имел время жизни c, но мы не можем гарантировать, что объект Server будет жить так долго.
Я решил это путем клонирования объекта Server и перемещения его в замыкание. Это нормально, так как все его данные уже отстали Arc
с.
Следующая проблема состояла в том, что self.connections.read().unwrap().insert(*id, stream);
необходимо получить блокировку write
, а не read
.
Наконец id+=1
необходимо разыменовать id
.
Как только они были исправлены, кажется, что сохранение TcpStream не является проблемой. (По крайней мере, с использованием ночных). Я подумал, что мне нужно запаковать TcpStream - но, похоже, все в порядке.
Вы можете видеть, что он компилирует на игровой площадке
use std::collections::HashMap;
use std::net::TcpListener;
use std::net::TcpStream;
use std::sync::{Arc, RwLock};
use std::thread;
#[derive(Clone, Debug)]
pub struct Server {
id: Arc<RwLock<u32>>,
connections: Arc<RwLock<HashMap<u32, TcpStream>>>,
url: String,
}
impl Server {
pub fn new(url: String) -> Server {
let server = Server {
id: Arc::new(RwLock::new(0)),
connections: Arc::new(RwLock::new(HashMap::new())),
url,
};
server
}
pub fn start(&self) {
let mut self_clone = self.clone();
thread::spawn(move || {
let mut listener =
TcpListener::bind(&self_clone.url).expect("Could not start the server");
println!("Server started succesfully");
for stream in listener.incoming() {
match stream {
Ok(stream) => self_clone.on_client_connect(stream),
Err(error) => eprintln!("Error when tried to use stream"),
}
}
});
}
fn on_client_connect(&mut self, stream: TcpStream) {
let id = self.id.read().unwrap();
self.connections.write().unwrap().insert(*id, stream);
let mut id = self.id.write().unwrap();
*id += 1;
}
}