我目前遇到的问题是创建一种将TCPListener从线程引用到主线程的Struct的方法.我试图实现的最终目标是一种从Server struct 引用服务器的TCP连接的方法.

以下是代码:

use std::io::Read;
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, mpsc, Mutex};
use std::thread;

fn main() {
    let server = Server::start("127.0.0.1:25565".to_string());
    loop {
        for client in server.connected_clients {
            println!("{:?}", client.stream.peer_addr().unwrap())
        }
    }
}

#[derive(Debug)]
struct Server {
    listener: Arc<Mutex<TcpListener>>,
    connected_clients: Vec<Client>,
}

impl Server {
    pub fn start(address: String) -> Server {
        let listener = TcpListener::bind(address).unwrap();

        let (tx, rx) = mpsc::channel();
        let listener = Arc::new(Mutex::new(listener));

        let server = Server {
            listener: listener,
            connected_clients: Vec::new()
        };

        tx.send(&server.listener).unwrap();

        thread::spawn(|| {
            let listener = rx.recv().unwrap();
            // For each new connection start a new thread
            for stream in listener.lock().unwrap().incoming() {
                let mut stream = stream.unwrap();
                thread::spawn(move || {
                    // TODO: Add client to the connected_clients Vec
                    let mut buffer = [0; 1024];
                    loop {
                        stream.read(&mut buffer).unwrap();
                        println!("{}", String::from_utf8(Vec::from(&buffer[..])).unwrap().trim_end_matches(char::from(0)));
                    }
                });
            }
        });

        server
    }
}

#[derive(Debug)]
struct Client {
    id: usize,
    stream: TcpStream,
}

错误:无法在线程之间安全共享std::sync::mpsc::Receiver&lt;&amp;Arc&lt;Mutex&gt;&gt;`

推荐答案

我不知道您是从哪里得到使用channel将对象发送到您刚刚产生的线程的 idea 的,但在这种情况下它肯定是不正确的.

只需使用move ||闭包来将外部变量移入其中即可.

考虑到这一点,下面的代码编译如下:(尽管我无法测试它是否工作)

use std::io::Read;
use std::net::{TcpListener, TcpStream};
use std::sync::{mpsc, Arc, Mutex};
use std::thread;

fn main() {
    let server = Server::start("127.0.0.1:25565".to_string());
    loop {
        for client in &server.connected_clients {
            println!("{:?}", client.stream.peer_addr().unwrap())
        }
    }
}

#[derive(Debug)]
struct Server {
    listener: Arc<Mutex<TcpListener>>,
    connected_clients: Vec<Client>,
}

impl Server {
    pub fn start(address: String) -> Server {
        let server = Server {
            listener: Arc::new(Mutex::new(TcpListener::bind(address).unwrap())),
            connected_clients: Vec::new(),
        };

        let listener = server.listener.clone();
        thread::spawn(move || {
            // For each new connection start a new thread
            for stream in listener.lock().unwrap().incoming() {
                let mut stream = stream.unwrap();
                thread::spawn(move || {
                    // TODO: Add client to the connected_clients Vec
                    let mut buffer = [0; 1024];
                    loop {
                        stream.read(&mut buffer).unwrap();
                        println!(
                            "{}",
                            String::from_utf8(Vec::from(&buffer[..]))
                                .unwrap()
                                .trim_end_matches(char::from(0))
                        );
                    }
                });
            }
        });

        server
    }
}

#[derive(Debug)]
struct Client {
    id: usize,
    stream: TcpStream,
}

从技术上讲,虽然在这种情况下完全是过度杀伤力,但您的channel方法也可以工作,但然后您必须发送对象的实际实例,而不是引用.并且您仍然需要使用move ||闭包来将rx对象移到其中.

use std::io::Read;
use std::net::{TcpListener, TcpStream};
use std::sync::{mpsc, Arc, Mutex};
use std::thread;

fn main() {
    let server = Server::start("127.0.0.1:25565".to_string());
    loop {
        for client in &server.connected_clients {
            println!("{:?}", client.stream.peer_addr().unwrap())
        }
    }
}

#[derive(Debug)]
struct Server {
    listener: Arc<Mutex<TcpListener>>,
    connected_clients: Vec<Client>,
}

impl Server {
    pub fn start(address: String) -> Server {
        let listener = TcpListener::bind(address).unwrap();

        let (tx, rx) = mpsc::channel();
        let listener = Arc::new(Mutex::new(listener));

        let server = Server {
            listener: listener,
            connected_clients: Vec::new(),
        };

        tx.send(server.listener.clone()).unwrap();

        thread::spawn(move || {
            let listener = rx.recv().unwrap();
            // For each new connection start a new thread
            for stream in listener.lock().unwrap().incoming() {
                let mut stream = stream.unwrap();
                thread::spawn(move || {
                    // TODO: Add client to the connected_clients Vec
                    let mut buffer = [0; 1024];
                    loop {
                        stream.read(&mut buffer).unwrap();
                        println!(
                            "{}",
                            String::from_utf8(Vec::from(&buffer[..]))
                                .unwrap()
                                .trim_end_matches(char::from(0))
                        );
                    }
                });
            }
        });

        server
    }
}

#[derive(Debug)]
struct Client {
    id: usize,
    stream: TcpStream,
}

最后一句话:

不过,我对整个 struct 的实用性提出了质疑.一旦您的线程进入for循环,您的listener就会被连续锁定,这意味着任何试图通过您的Server对象实际访问它的人都将死锁.

Rust相关问答推荐

阻止websocket中断的中断中断的终端(操作系统错误4)

go 掉包装 struct 中的泛型

铁 rust 中的共享对象实现特征

一种随机局部搜索算法的基准(分数)

为什么TcpListener的文件描述符和生成的TcpStream不同?

如何将单个 struct 实例与插入器一起传递到Rust中的映射

在生存期内将非静态可变引用转换为范围内的静态可变引用

Rust移动/复制涉及实际复制时进行检测

Rust从关联函数启动线程

确保参数是编译时定义的字符串文字

信号量释放后 Rust 输出挂起线程

如何在 Rust 中打印 let-else 语句中的错误?

相当于 Rust 中 C++ 的 std::istringstream

部署Rust发布二进制文件的先决条件

使用在功能标志后面导入的类型,即使未启用功能标志

没有得到无法返回引用局部变量`queues`的值返回引用当前函数拥有的数据的值的重复逻辑

将原始可变指针传递给 C FFI 后出现意外值

为什么我可以在没有生命周期问题的情况下内联调用 iter 和 collect?

为什么当borrow 变量发生变化时,borrow 变量不会改变?

返回引用的返回函数