2016-11-25 65 views
0

我正在寫一個簡單的websocket服務器名爲BoltServer基於Rust websocket箱(代碼是不完整的,我剛剛開始)。我正在使用示例程序作爲基礎。然而,示例程序不是模塊化的(具有很長的方法)。所以我試圖把它們分解成結構和方法。我想爲每個客戶端產生兩個線程。一個發送消息,另一個接收消息。所以在這裏,我想捕獲線程在結構中使用的所有變量,然後在impl中調用run方法。避免封閉 - 封裝線程變量結構

extern crate websocket; 
extern crate time; 
extern crate rustc_serialize; 

pub mod ws { 
    use std::thread; 
    use std::sync::{Arc, Mutex}; 
    use std::sync::mpsc; 
    use std::net::ToSocketAddrs; 
    use websocket; 
    use websocket::{Server, Message, Sender, Receiver}; 
    use websocket::server::Connection; 
    use websocket::stream::WebSocketStream; 
    use std::str::from_utf8; 

    struct BoltUser { 
     user_id: u32, 
     my_tx: mpsc::Sender<String>, 
    } 

    struct Broadcaster { 
     my_rx: mpsc::Receiver<String>, 
    } 
    impl Broadcaster { 
     fn new(receiver: mpsc::Receiver<String>) -> Broadcaster { 
      Broadcaster { my_rx: receiver } 
     } 
     fn run(self) { 
      while let Ok(msg) = self.my_rx.recv() { 
       println!("Broadcaster got message: {}", msg); 
      } 
     } 
    } 

    struct SocketReader {} 
    impl SocketReader { 
     fn run(self) {} 
    } 

    struct SocketWriter { 
     my_rx: mpsc::Receiver<String>, 
     sender: Sender, 
    } 
    impl SocketWriter { 
     fn run(self) { 
      while let Ok(message) = self.my_rx.recv() { 
      } 
     } 
    } 

    pub struct BoltServer { 
     address: String, 
     connected_users: Arc<Mutex<Vec<BoltUser>>>, 
    } 
    impl BoltServer { 
     pub fn new(address: &str) -> BoltServer { 
      BoltServer { 
       address: address.to_string(), 
       connected_users: Arc::new(Mutex::new(vec![])), 
      } 
     } 
     fn handshake(&mut self, 
        connection: Connection<WebSocketStream, WebSocketStream>) 
        -> (SocketWriter, SocketReader) { 
      let request = connection.read_request().unwrap(); 
      // println!("thread-> Accepting request..."); 
      let response = request.accept(); 
      let (mut sender, mut receiver) = response.send().unwrap().split(); 
      let (user_tx, user_rx) = mpsc::channel::<String>();//Create a channel for writer 
      let socket_writer = SocketWriter { 
       my_rx: user_rx, 
       sender: sender, 
      }; 
      let socket_reader = SocketReader {}; 
      (socket_writer, socket_reader) 
     } 
     pub fn start(&mut self) { 
      println!("Starting"); 
      let (broadcaster_tx, broadcaster_rx) = mpsc::channel::<String>(); 
      let broadcaster = Broadcaster::new(broadcaster_rx); 
      let handle = thread::Builder::new() 
       .name("Broadcaster".to_string()) 
       .spawn(move || broadcaster.run()); 

      let server = Server::bind(&*self.address).unwrap(); 

      let mut user_id: u32 = 0; 

      // Block and process connection request from a new client 
      for connection in server { 
       user_id = user_id + 1;//Create a new user id 
       let (socket_writer, socket_reader) = self.handshake(connection); 
       thread::Builder::new() 
        .name("Socket writer".to_string()) 
        .spawn(move || socket_writer.run()); 
       thread::Builder::new() 
        .name("Socket reader".to_string()) 
        .spawn(move || socket_reader.run()); 
      } 

      handle.unwrap().join(); 
      println!("Finished"); 
     } 
    } 
} 

下面的代碼給出了我想要實現的想法。

// Block and process connection request from a new client 
for connection in server { 
    user_id = user_id + 1;//Create a new user id 
    let (socket_writer, socket_reader) = self.handshake(connection); 
    thread::Builder::new().name("Socket writer".to_string()).spawn(move || { 
     socket_writer.run() 
    }); 
    thread::Builder::new().name("Socket reader".to_string()).spawn(move || { 
     socket_reader.run() 
    }); 
} 

這裏我卡在握手方法。我無法通過調用庫中的split方法來初始化具有發件人的SocketWriter結構。我正在以下編譯錯誤:

error[E0038]: the trait `websocket::Sender` cannot be made into an object 
    --> src/lib.rs:46:9 
    | 
46 |   sender:Sender, 
    |   ^^^^^^^^^^^^^ the trait `websocket::Sender` cannot be made into an object 
    | 
    = note: method `send_dataframe` has generic type parameters 
    = note: method `send_message` has generic type parameters 

回答

0

錯誤是告訴你眼前的問題:

46 |   sender:Sender, 
    |   ^^^^^^^^^^^^^ the trait `websocket::Sender` cannot be made into an object 

首先,可變/場不能有一個普通的特徵類型(但&Trait可能的話),而且websocket::Sender的性狀不是object safe;它具有不能動態工作的通用方法(即,vtable方法必須具有固定類型)。

相反,你必須有一個具體的類型(你也可以使它成爲一個通用的結構)。

什麼是正確的類型並不明顯,所以我想讓編譯器告訴我。所以首先嚐試最簡單的可能:

sender:(), 

編譯器的一些信息回覆:

|      ^^^^^^ expected(), found struct `websocket::client::Sender` 

好吧,讓我們插上在:

sender: websocket::client::Sender, 

這給:

46 |   sender: websocket::client::Sender, 
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type arguments, found 0 

好的,這是一個通用類型。下一步嘗試:

sender: websocket::client::Sender<()>, 

最後,它給我們的真正類型:

74 |    sender:sender, 
    |      ^^^^^^ expected(), found enum `websocket::WebSocketStream` 

所以最後我們就可以完成SocketWriter

struct SocketWriter { 
    my_rx: mpsc::Receiver<String>, 
    sender: websocket::client::Sender<websocket::WebSocketStream>, 
} 

有一個以下編譯錯誤,因爲connection你得到的是一個Result<>所以你需要檢查錯誤(它編譯如果我改爲self.handshake(connection.unwrap()),但這顯然不是最好的實踐冰。

+0

謝謝。你是如何找到具體類型的? websocket API文檔沒有提到它。 – Steve

+0

我已經更新了我的工作答案。 –