2017-08-14 35 views
0

我想做消息廣播:當其中一個客戶端發送消息時,服務器將它寫入每個套接字。我的主要問題是我無法弄清楚如何發送Vec到線程。我不能使用Mutex,因爲這會將其他線程的訪問鎖定到Vec進行讀取。我無法克隆和發送,因爲無法克隆和發送TcpStream。這裏是我的嘗試到現在爲止只要其中一個讀取新輸入,我可以維護一個TcpStream的Vec來跨線程寫入它們嗎?

use std::net::{TcpStream, TcpListener}; 
use std::io::prelude::*; 
use std::sync::{Arc, Mutex}; 
use std::thread; 
use std::sync::mpsc::{channel, Receiver}; 
use std::cell::RefCell; 

type StreamSet = Arc<RefCell<Vec<TcpStream>>>; 
type StreamReceiver = Arc<Mutex<Receiver<StreamSet>>>; 

fn main() { 
    let listener = TcpListener::bind("0.0.0.0:8000").unwrap(); 
    let mut connection_set: StreamSet = Arc::new(RefCell::new(vec![])); 
    let mut id = 0; 
    let (tx, rx) = channel(); 
    let rx = Arc::new(Mutex::new(rx)); 
    for stream in listener.incoming() { 
     let receiver = rx.clone(); 
     let stream = stream.unwrap(); 
     (*connection_set).borrow_mut().push(stream); 
     println!("A connection established with client {}", id); 
     thread::spawn(move || handle_connection(receiver, id)); 
     id += 1; 
     tx.send(connection_set.clone()).unwrap(); 
    } 

} 

fn handle_connection(rx: StreamReceiver, id: usize) { 
    let streams; 
    { 
     streams = *(rx.lock().unwrap().recv().unwrap()).borrow(); 
    } 
    let mut connection = &streams[id]; 
    loop { 
     let mut buffer = [0; 512]; 
     if let Err(_) = connection.read(&mut buffer) { 
      break; 
     }; 
     println!("Request: {}", String::from_utf8_lossy(&buffer[..])); 
     if let Err(_) = connection.write(&buffer[..]) { 
      break; 
     }; 
     if let Err(_) = connection.flush() { 
      break; 
     }; 
    } 
} 

回答

1

另一個想法是產生一個單一的「控制器」線程每一個插座一個線程。每個線程都擁有套接字,並有一個通道將數據發送回控制器。控制器將擁有一個Vec的通道發送給每個線程。當一個線程接收到數據時,將其發送給控制器,該控制器將其複製併發送回每個工作線程。您可以將數據包裝在Arc中以防止不必要的重複,並且您應該提供一個ID以避免將數據回送給原始發件人(如果需要的話)。

這將在一個線程內完全移動所有權,這應該避免您遇到的問題。

你也可以看看Tokio,它應該允許你做類似的事情,但不需要在1-1映射中產生線程。

我不能使用Mutex,因爲這將鎖定其他線程

的訪問你總是可以嘗試不同的鎖定機構,諸如RwLock

因爲TcpStream無法克隆當然

它可以:TcpStream::try_clone

+0

啊謝謝。我實際上對編碼比較陌生,將在下個月完成一年。所以我試圖在使用像tokio這樣的抽象之前盡我所能地自己實現它,所以我明白了底下發生了什麼。我將嘗試實施控制器工作者模型。每個單獨的線程是否有單獨的通道,或者它們是否使用相同的接收器,發送器對? – codeNoob

+0

我期望控制器線程爲每個工作線程有一個唯一的通道向它們發送數據,然後是從每個工作人員返回到控制器的重用通道(因爲它們是** m ** ultiple ** p ** roducer ,** s ** ingle ** c ** onsumer頻道)。總共應該有N + 1個通道。 – Shepmaster

+0

啊好的。說得通。謝謝。 – codeNoob

相關問題