多个WebSocket服务器在rust

deikduxw  于 2022-11-11  发布在  其他
关注(0)|答案(2)|浏览(291)

我参考了this,也尝试了tungstenite library。但我一次只能运行一个服务器,它捕获了整个线程。
我试着在不同的线程上运行多个服务器,但从来没有听过任何东西,只是退出程序。
有没有什么方法可以让我在不同的端口上运行多个WebSocket服务器,并在运行时创建、销毁一个服务器?
编辑:如果我在主线程上运行一个服务器,在另一个线程上运行另一个服务器,它会工作,看起来我必须以某种方式保持主线程忙碌......但有没有更好的方法?
下面是一些示例代码:
它使用:

use std::net::TcpListener;
use std::thread::spawn;
use tungstenite::accept;

这是阻止主线程的正常代码

let server = TcpListener::bind("127.0.0.1:9002").expect("err: ");
        for stream in server.incoming() {
            spawn(move || {
                let mut websocket = accept(stream.unwrap()).unwrap();
                loop {
                    let msg = websocket.read_message().unwrap();

                    println!("{}", msg);

                    // We do not want to send back ping/pong messages.
                    if msg.is_binary() || msg.is_text() {
                        websocket.write_message(msg).unwrap();
                    }
                }
            });
        }

下面是带线程的代码:

spawn(|| {
        let server = TcpListener::bind("127.0.0.1:9001").expect("err: ");
        for stream in server.incoming() {
            spawn(move || {
                let mut websocket = accept(stream.unwrap()).unwrap();
                loop {
                    let msg = websocket.read_message().unwrap();

                    println!("{}", msg);

                    // We do not want to send back ping/pong messages.
                    if msg.is_binary() || msg.is_text() {
                        websocket.write_message(msg).unwrap();
                    }
                }
            });
        }
    });

但是上面的代码需要主线程来运行,我确实能够在不同的线程上运行多个服务器,但是需要一些东西来占用主线程。

igetnqfo

igetnqfo1#

Rust程序在main()结束时终止。您需要做的是等待,直到您的辅助线程完成。
std::thread::spawn返回一个JoinHandle,它有一个join方法来完成这个任务-它等待(阻塞)直到句柄所引用的线程完成,如果线程出现混乱,则返回一个错误。
因此,只要有线程在运行,就需要收集所有这些句柄,然后一个接一个地对它们执行join()操作。与忙循环不同,这不会不必要地浪费CPU资源。

use std::net::TcpListener;
use std::thread::spawn;
use tungstenite::accept;

fn main() {
    let mut handles = vec![];

    // Spawn 3 identical servers on ports 9001, 9002, 9003
    for i in 1..=3 {
        let handle = spawn(move || {
            let server = TcpListener::bind(("127.0.0.1", 9000 + i)).expect("err: ");
            for stream in server.incoming() {
                spawn(move || {
                    let mut websocket = accept(stream.unwrap()).unwrap();
                    loop {
                        let msg = websocket.read_message().unwrap();

                        println!("{}", msg);

                        // We do not want to send back ping/pong messages.
                        if msg.is_binary() || msg.is_text() {
                            websocket.write_message(msg).unwrap();
                        }
                    }
                });
            }
        });
        handles.push(handle);
    }

    // Wait for each thread to finish before exiting
    for handle in handles {
        if let Err(e) = handle.join() {
            eprintln!("{:?}", e)
        }
    }
}
vc9ivgsu

vc9ivgsu2#

当你在一个线程(或多个线程)中做所有的工作而主线程无事可做时,通常它被设置为等待(join)那个线程。
这样做的另一个好处是,如果你的辅助线程结束或崩溃,那么你的程序也会结束。或者你可以把整个 create-thread/join-thread Package 在一个循环中,使它更有弹性:

fn main() {
    loop {
        let th = std::thread::spawn(|| {
            // Do the real work here
            std::thread::sleep(std::time::Duration::from_secs(1));
            panic!("oh!");
        });
        if let Err(e) = th.join() {
            eprintln!("Thread panic: {:?}", e)
        }
    }
}

链接到playground,我已经将循环更改为for _ in ..3,因为playgrond不喜欢无限循环。

相关问题