mio

Module guide

Source
Expand description

§Getting started guide.

In this guide we’ll do the following:

  1. Create a Poll instance (and learn what it is).
  2. Register an event source.
  3. 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
}