I'm looking to build multiple concurrent servers on different ports with Rust and 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();
Is there an option with Tokio to listen to multiple ports or do I need to create a simple thread for each port and run Core::new()
in each?
Thanks to rust-scoped-pool, I have:
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 is the only solution I have found to execute multiple threads and wait forever after spawning them. I think it's working but I was wondering if a simpler solution existed.
You can run multiple servers from one thread. core.run(server).unwrap();
is just a convenience method and not the only/main way to do things.
Instead of running the single ForEach
to completion, spawn each individually and then just keep the thread alive:
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);
}
I'd just like to follow up that there seems to be a slightly less manual way to do things than 46bit's answer (at least as of 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();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With