Rust Network Errors
A network error is an io::Error value from a std::net call. kind() names the failure that happened.
Nobody is listening
Connect to a port with no server behind it. The error names itself:
let err = TcpStream::connect(("127.0.0.1", closed_port)).unwrap_err();
println!("kind = {:?}", err.kind());Two sockets, one port
The second bind on a held address fails at once:
let second = TcpListener::bind(addr);
println!("second bind = {:?}", second.unwrap_err().kind());An address this machine does not have
192.0.2.1 is a documentation address. No machine owns it locally, so binding to it fails:
let foreign = TcpListener::bind("192.0.2.1:0");
println!("foreign bind = {:?}", foreign.unwrap_err().kind());Branch on the kind
A match on kind() turns raw errors into clear reports. This run met a refused connection:
match err.kind() {
ErrorKind::ConnectionRefused => println!("report: the server is down"),
ErrorKind::AddrInUse => println!("report: that port is taken"),
_ => println!("report: something else went wrong"),
}Example
use std::net::{TcpListener, TcpStream};
fn main() {
let first = TcpListener::bind("127.0.0.1:0").unwrap();
let addr = first.local_addr().unwrap();
let second = TcpListener::bind(addr);
println!("second bind = {:?}", second.unwrap_err().kind());
drop(first);
let refused = TcpStream::connect(addr);
let err = refused.unwrap_err();
println!("connect after close = {:?}", err.kind());
println!("refused os code = {:?}", err.raw_os_error());
let foreign = TcpListener::bind("192.0.2.1:0");
println!("foreign bind = {:?}", foreign.unwrap_err().kind());
}Key points
- Every fallible std::net call returns io::Result.
- A failure is a value you can inspect, not a crash
- ConnectionRefused: nothing listens at that address.
- The other machine answered and refused the connection
- AddrInUse: bind asked for a port that a live socket already holds
- AddrNotAvailable: the IP half is not an address of this machine.
- There is nothing local to bind to
- Use err.kind() to branch on a failure.
- Match kinds, not message text.
- Text differs between systems
In this example, one listener sets three traps. A second bind on its address fails with AddrInUse. The port is already spoken for. Then the first listener drops. A connect to its old address is refused at once: ConnectionRefused, with Linux code 111 inside. The last bind asks for 192.0.2.1, an address this machine does not own. That fails with AddrNotAvailable. Three failures, three kinds, and not one panic.
Note
The error also carries the raw OS code.
On Linux, raw_os_error() is Some(111) for a refused connection.
Kinds are the portable layer above the codes.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท Rust Playground
Exercise
A deploy tool must report "server down" and "my port is taken" as different problems. What should it match on?