我试图使用Rust-Websocket创建一个简单的聊天室,让多个人可以互相交谈。
我查看了示例和' server.rs'和' websockets.html'看起来对我来说是一个不错的起点。所以我只是尝试启动它并从网络连接。一切正常但我只能与自己沟通,而不能与其他连接沟通(因为它将消息直接发送回sender
而不是每个连接。)
所以我试图获得一个包含所有senders
/ clients
的向量,这样我就可以迭代它们并将消息发送给每个人,但这似乎有问题。我无法传达sender
或client
,因为它不是线程安全的,我也无法复制其中任何一个。
我不确定我是否只是不了解100%的全部借款,或者它是否打算不进行这样的交叉连接通信。
server.rs:
https://github.com/cyderize/rust-websocket/blob/master/examples/server.rs
websockets.html:
https://github.com/cyderize/rust-websocket/blob/master/examples/websockets.html
我可能会从错误的方向接近这个。与所有其他线程共享收到的消息可能更容易。我想到了这一点,但我唯一能想到的是使用channels
从线程内部向外部发送消息。有没有办法在线程之间直接广播消息?我需要做的就是从一个线程向另一个线程发送一个字符串。
答案 0 :(得分:1)
所以这并不像人们想象的那么直截了当。
基本上我使用的调度程序线程就像所有连接客户端的控制中心一样。因此,每当客户端收到消息时,它就会发送给调度程序,然后将消息分发给每个连接的客户端。
我还必须在另一个线程中接收消息,因为没有非阻塞方式来接收rust-websocket中的消息。然后,我可以使用永久循环来检查从websocket和调度程序收到的新消息。
以下是我的代码最终的样子:
extern crate websocket;
use std::str;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::thread;
use websocket::{Server, Message, Sender, Receiver};
use websocket::header::WebSocketProtocol;
use websocket::message::Type;
fn main() {
let server = Server::bind("0.0.0.0:2794").unwrap();
let (dispatcher_tx, dispatcher_rx) = mpsc::channel::<String>();
let client_senders: Arc<Mutex<Vec<mpsc::Sender<String>>>> = Arc::new(Mutex::new(vec![]));
// dispatcher thread
{
let client_senders = client_senders.clone();
thread::spawn(move || {
while let Ok(msg) = dispatcher_rx.recv() {
for sender in client_senders.lock().unwrap().iter() {
sender.send(msg.clone()).unwrap();
}
}
});
}
// client threads
for connection in server {
let dispatcher = dispatcher_tx.clone();
let (client_tx, client_rx) = mpsc::channel();
client_senders.lock().unwrap().push(client_tx);
// Spawn a new thread for each connection.
thread::spawn(move || {
let request = connection.unwrap().read_request().unwrap(); // Get the request
let headers = request.headers.clone(); // Keep the headers so we can check them
request.validate().unwrap(); // Validate the request
let mut response = request.accept(); // Form a response
if let Some(&WebSocketProtocol(ref protocols)) = headers.get() {
if protocols.contains(&("rust-websocket".to_string())) {
// We have a protocol we want to use
response.headers.set(WebSocketProtocol(vec!["rust-websocket".to_string()]));
}
}
let mut client = response.send().unwrap(); // Send the response
let ip = client.get_mut_sender()
.get_mut()
.peer_addr()
.unwrap();
println!("Connection from {}", ip);
let message: Message = Message::text("SERVER: Connected.".to_string());
client.send_message(&message).unwrap();
let (mut sender, mut receiver) = client.split();
let(tx, rx) = mpsc::channel::<Message>();
thread::spawn(move || {
for message in receiver.incoming_messages() {
tx.send(message.unwrap()).unwrap();
}
});
loop {
if let Ok(message) = rx.try_recv() {
match message.opcode {
Type::Close => {
let message = Message::close();
sender.send_message(&message).unwrap();
println!("Client {} disconnected", ip);
return;
},
Type::Ping => {
let message = Message::pong(message.payload);
sender.send_message(&message).unwrap();
},
_ => {
let payload_bytes = &message.payload;
let payload_string = match str::from_utf8(payload_bytes) {
Ok(v) => v,
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
};
let msg_string = format!("MESSAGE: {}: ", payload_string);
dispatcher.send(msg_string).unwrap();
}
}
}
if let Ok(message) = client_rx.try_recv() {
let message: Message = Message::text(message);
sender.send_message(&message).unwrap();
}
}
});
}
}