Open
Description
If TcpListener
is in non-blocking mode then accepted streams inherit this property on all platforms except Linux, where accept4
is used instead of accept
.
This code (with commented out stream.set_nonblocking(false)
) unexpectedly works as expected on Linux only, because stream
is in blocking mode.
let listener = TcpListener::bind("0.0.0.0:3333").unwrap();
listener.set_nonblocking(true).expect("set nonblocking");
println!("Server listening on port 3333");
loop {
match listener.accept() {
Ok((mut stream, _)) => {
println!("New connection");
//stream.set_nonblocking(false).expect("nonblock");
stream
.set_read_timeout(Some(Duration::from_secs(10)))
.expect("set timeout");
let mut data = [0 as u8; 2];
match stream.read_exact(&mut data) {
Ok(_) => println!("Got message!"),
Err(e) => println!("Failed to receive data: {:?}", e),
}
}
Err(_e) => {
println!("Error: {:?}", e);
}
}
}
accept4
man page explains:
On Linux, the new socket returned by accept() does not inherit file status
flags such as O_NONBLOCK and O_ASYNC from the listening socket.
This behavior differs from the canonical BSD sockets implementation.
Portable programs should not rely on inheritance or noninheritance
of file status flags and always explicitly set all required flags on the socket
returned from accept().
I agree that code above should also set non_blocking explicitly, at the same time it would be nice to behave the same way on all platoftms.
Meta
rustc --version --verbose
rustc 1.37.0 (eae3437 2019-08-13)
binary: rustc
commit-hash: eae3437
commit-date: 2019-08-13
host: x86_64-unknown-linux-gnu
release: 1.37.0
LLVM version: 8.0
(but it applies to multiple versions)