如何使用Rust和Tokio构建多个并发服务器?

8
我希望使用Rust和Tokio构建多个并发服务器,这些服务器会在不同的端口上运行:
let mut core = Core::new().unwrap();
let handle = core.handle();

// I want to bind to multiple port here if it's possible with simple addresses
let addr = "127.0.0.1:80".parse().unwrap();
let addr2 = "127.0.0.1:443".parse().unwrap();

// Or here if there is a special function on the TcpListener
let sock = TcpListener::bind(&addr, &handle).unwrap();

// Or here if there is a special function on the sock
let server = sock.incoming().for_each(|(client_stream, remote_addr)| {
    // And then retrieve the current port in the callback
    println!("Receive connection on {}!", mysterious_function_to_retrieve_the_port);
    Ok(())
});

core.run(server).unwrap();

有没有使用Tokio监听多个端口的选项,或者我需要为每个端口创建一个简单的线程,并在每个线程中运行Core::new()

感谢rust-scoped-pool,我现在可以:

let pool = Pool::new(2);

let mut listening_on = ["127.0.0.1:80", "127.0.0.1:443"];

pool.scoped(|scope| {
    for address in &mut listening_on {
        scope.execute(move ||{
            let mut core = Core::new().unwrap();
            let handle = core.handle();

            let addr = address.parse().unwrap();
            let sock = TcpListener::bind(&addr, &handle).unwrap();

            let server = sock.incoming().for_each(|(client_stream, remote_addr)| {
                println!("Receive connection on {}!", address);
                Ok(())
            });

            core.run(server).unwrap();
        });
    }
});

rust-scoped-pool是我找到的唯一解决方案,可用于执行多个线程并在它们被生成后永久等待。我认为它起作用了,但我想知道是否存在更简单的解决方案。


我对叙述和示例代码感到困惑。您能否澄清您需要的是(1)一个服务器对象监听多个端口还是(2)多个服务器对象每个监听一个端口? - Matthieu M.
我想要一个服务器对象监听多个端口,但是这个服务器必须能够访问所选择的端口。 - Thibaud Dauce
我在我的主贴中编辑了我的当前进展。 - Thibaud Dauce
2个回答

4

我想跟进一下,似乎有一种比46bit的回答稍微不那么手动的方法(至少截至2019年)。

let addr1 = "127.0.0.1:80".parse().unwrap();
let addr2 = "127.0.0.1:443".parse().unwrap();

let sock1 = TcpListener::bind(&addr1, &handle).unwrap();
let sock2 = TcpListener::bind(&addr2, &handle).unwrap();

let server1 = sock1.incoming().for_each(|_| Ok(()));
let server2 = sock2.incoming().for_each(|_| Ok(()));

let mut runtime = tokio::runtime::Runtime()::new().unwrap();

runtime.spawn(server1);
runtime.spawn(server2);

runtime.shutdown_on_idle().wait().unwrap();

4
你可以从一个线程中运行多个服务器。 core.run(server).unwrap(); 只是一种方便的方法,而不是唯一/主要的方法。
不要运行单个 ForEach 直到完成,而是将每个服务器单独生成并保持线程活动状态:
let mut core = Core::new().unwrap();
let handle = core.handle();

// I want to bind to multiple port here if it's possible with simple addresses
let addr = "127.0.0.1:80".parse().unwrap();
let addr2 = "127.0.0.1:443".parse().unwrap();

// Or here if there is a special function on the TcpListener
let sock = TcpListener::bind(&addr, &handle).unwrap();

// Or here if there is a special function on the sock
let server = sock.incoming().for_each(|(client_stream, remote_addr)| {
    // And then retrieve the current port in the callback
    println!("Receive connection on {}!", mysterious_function_to_retrieve_the_port);
    Ok(())
});

handle.spawn(sock);
handle.spawn(server);

loop {
    core.turn(None);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接