Reputation: 6353
Consider the following code:
extern crate tokio; // Executor runtime
use tokio::prelude::*;
use tokio::net::TcpListener;
use std::net::SocketAddr;
fn main() {
let addr = "127.0.0.1:8118".parse::<SocketAddr>().unwrap();
let listener = TcpListener::bind(&addr)
.expect("unable to bind TCP listener");
tokio::run(listener.incoming()
.map_err(|e| eprintln!("failed to accept socket; error = {:?}", e))
.for_each(|mut socket| {
let mut buf = vec![];
socket.read_to_end(&mut buf).unwrap();
println!("Received: {:#?}", buf);
Ok(())
})
);
}
When I run this and send something to port 8118 I get the following error:
thread 'tokio-runtime-worker-0' panicked at 'called `Result::unwrap()` on an `Err` value: Kind(WouldBlock)', src/libcore/result.rs:997:5
I imagine there is some way to put to put my socket in blocking mode, or perhaps catch the error and do something with it. I wonder what the standard, canonical way to approach this problem is.
I'd rather not block, since I want the server to do other things while waiting for clients, so an async / threaded solution would be fantastic.
Upvotes: 0
Views: 3980
Reputation: 431069
You are using Tokio, a library where the entire purpose is to enable asynchronous IO. You never want to perform blocking operations in the asynchronous event loop.
Instead, either go all-in on async or avoid it completely and use simpler, coarser threads.
Tokio's io::read_to_end
creates a future that is capable of reading all the data from a socket:
use std::net::SocketAddr;
use tokio::{net::TcpListener, prelude::*}; // 0.1.22
fn main() {
let addr = "127.0.0.1:8118".parse::<SocketAddr>().unwrap();
let listener = TcpListener::bind(&addr).expect("unable to bind TCP listener");
tokio::run(
listener
.incoming()
.and_then(|s| tokio::io::read_to_end(s, vec![]))
.map_err(|e| panic!("failed: {:?}", e))
.for_each(|(_socket, buf)| {
println!("Received: {:#?}", buf);
Ok(())
}),
);
}
See also:
Upvotes: 1