tcp - 我可以维护一个 TcpStreams 的 Vec 以在其中一个读取新输入时跨线程写入它们吗?

标签 tcp rust tcpserver

我想进行消息广播:当其中一个客户端发送消息时,服务器将其写入每个套接字。我的主要问题是我不知道如何将 Vec 发送到线程。我不能使用 Mutex,因为这会锁定其他线程对 Vec 的访问以进行读取。我无法克隆和发送,因为无法克隆和发送 TcpStream。这是我到目前为止的尝试

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;
        };
    }
}

最佳答案

另一个想法是为每个套接字生成一个“ Controller ”线程一个线程。每个线程都将拥有套接字并有一个 channel 将数据发送回 Controller 。 Controller 将拥有一个 Vec channel 以发送到每个线程。当线程接收到数据时,您将其发送到 Controller , Controller 复制它并将其发送回每个工作线程。您可以将数据包装在 Arc 中以防止不必要的重复,并且您应该提供一个 ID 以避免将数据回传给原始发件人(如果需要)。

这会将所有权完全转移到一个线程中,这应该可以避免您遇到的问题。

您可能还希望查看 Tokio ,这应该允许您执行类似的操作,但无需在 1-1 映射中生成线程。

I can't use Mutex because that will lock the access of other threads

您始终可以尝试不同的锁定机制,例如 RwLock .

because TcpStream can't be cloned

当然可以:TcpStream::try_clone .

关于tcp - 我可以维护一个 TcpStreams 的 Vec 以在其中一个读取新输入时跨线程写入它们吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45673552/

相关文章:

C# Socket.receive 连续接收0字节,循环不阻塞

Python:具有公共(public) IP 的 TCP 服务器

C# 客户端/服务器从服务器返回应答给客户端

rust - 如何阅读打印品前的文字!信息?

rust - 自有指针移动的语义

arrays - 初始化固定长度数组的正确方法是什么?

linux - 非阻塞 tcp 与 epoll 连接

tcp - udp打洞后发送文件

python - 如何使用 asyncio 创建 TCP 代理服务器?

c# - C# 中的 TCP 服务器 Windows 8 XAML 应用程序