我正在创建一个服务器,该服务器将TcpStream对象存储在稍后使用的Vec中。问题是监听新连接并将其添加到Vec的函数永远在单独的线程中运行,并且不允许其他线程读取Vec。
pub struct Server {
pub connections: Vec<TcpStream>,
}
impl Server {
fn listen(&mut self) {
println!("Server is listening on port 8080");
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
loop {
let stream = listener.accept().unwrap().0;
println!("New client connected: {}", stream.peer_addr().unwrap());
//should block for write here
self.connections.push(stream);
//should release write lock
}
}
pub fn run(self) {
let arc_self = Arc::new(RwLock::new(self));
let arc_self_clone = arc_self.clone();
//blocks the lock for writing forever because of listen()
let listener_thread = thread::spawn(move || arc_self_clone.write().unwrap().listen());
loop {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
if input.trim() == "1" {
//can't read because lock blocked for writing
for c in &arc_self.read().unwrap().connections {
println!("testing...");
}
}
}
}
}
在当前示例中,服务器接受连接,但不允许主线程读取连接向量。我想让listen函数以固定的间隔(1-5s)运行,所以它允许其他线程在那个时间读取向量,但是listener.accept()阻塞了线程,所以我认为这不是一个有效的解决方案。如果可能的话,我也希望它永远运行,并且只在需要写(新客户端连接)并且等待客户端连接时阻止对向量的访问,而不是阻止其他线程对连接向量的读访问。
您可以将connections
包装在RwLock
中而不是整个self
中,如下所示,但我建议使用适当的同步原语,如channel
。
pub struct Server {
pub connections: RwLock<Vec<TcpStream>>,
}
impl Server {
fn listen(&self) {
println!("Server is listening on port 8080");
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
loop {
let stream = listener.accept().unwrap().0;
println!("New client connected: {}", stream.peer_addr().unwrap());
//should block for write here
self.connections.write().unwrap().push(stream);
//should release write lock
}
}
pub fn run(self) {
let arc_self = Arc::new(self);
let arc_self_clone = arc_self.clone();
let listener_thread = thread::spawn(move || arc_self_clone.listen());
loop {
let mut input = String::new();
io::stdin().read_line(&mut input).unwrap();
if input.trim() == "1" {
for c in &*arc_self.connections.try_read().unwrap() {
println!("testing...");
}
}
}
}
}