Expand description
§Getting started guide.
In this guide we’ll do the following:
- Create a
Poll
instance (and learn what it is). - Register an event source.
- Create an event loop.
At the end you’ll have a very small (but quick) TCP server that accepts connections and then drops (disconnects) them.
§1. Creating a Poll
instance
Using Mio starts by creating a Poll
instance, which monitors events
from the OS and puts them into Events
. This allows us to execute I/O
operations based on what operations are ready.
// `Poll` allows for polling of readiness events.
let poll = Poll::new()?;
// `Events` is collection of readiness `Event`s and can be filled by
// calling `Poll::poll`.
let events = Events::with_capacity(128);
For example if we’re using a TcpListener
, we’ll only want to
attempt to accept an incoming connection iff any connections are
queued and ready to be accepted. We don’t want to waste our time if no
connections are ready.
§2. Registering event source
After we’ve created a Poll
instance that monitors events from the OS
for us, we need to provide it with a source of events. This is done by
registering an event source. As the name “event source” suggests it is
a source of events which can be polled using a Poll
instance. On Unix
systems this is usually a file descriptor, or a socket/handle on
Windows.
In the example below we’ll use a TcpListener
for which we’ll receive
an event (from Poll
) once a connection is ready to be accepted.
// Create a `TcpListener`, binding it to `address`.
let mut listener = TcpListener::bind(address)?;
// Next we register it with `Poll` to receive events for it. The `SERVER`
// `Token` is used to determine that we received an event for the listener
// later on.
const SERVER: Token = Token(0);
poll.registry().register(&mut listener, SERVER, Interest::READABLE)?;
Multiple event sources can be registered (concurrently), so we can monitor multiple sources at a time.
§3. Creating the event loop
After we’ve created a Poll
instance and registered one or more
event sources with it, we can poll it for events. Polling for events
is simple, we need a container to store the events: Events
and need
to do something based on the polled events (this part is up to you, we
can’t do it all!). If we do this in a loop we’ve got ourselves an event
loop.
The example below shows the event loop in action, completing our small TCP server.
// Start our event loop.
loop {
// Poll the OS for events, waiting at most 100 milliseconds.
poll.poll(&mut events, Some(Duration::from_millis(100)))?;
// Process each event.
for event in events.iter() {
// We can use the token we previously provided to `register` to
// determine for which type the event is.
match event.token() {
SERVER => loop {
// One or more connections are ready, so we'll attempt to
// accept them (in a loop).
match listener.accept() {
Ok((connection, address)) => {
println!("Got a connection from: {}", address);
},
// A "would block error" is returned if the operation
// is not ready, so we'll stop trying to accept
// connections.
Err(ref err) if would_block(err) => break,
Err(err) => return Err(err),
}
}
}
}
}
fn would_block(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::WouldBlock
}