Episode 003 – Intro to Asio

This episode will provide a quick introduction to the Asio library and a small amount of asynchronous programming in general. Future episodes will continue this work by introducing additional libraries and talking to actual web services. For now we’ll start by building a small app that resolves hostnames into IP addresses. The gflags and glog libraries will provide some helpful infrastructure to get things started. Take a look at Episode 002 to refresh your memory of how they work.

Asio’s fundamental component is the io_service class. This class provides an execution context to run all of the library’s asynchronous operations. The easiest way to understand io_service is to look at io_service::post(). Calling this method will push a function (a closure really) for execution when the io_service gets around to running it. It will sit enqueued until the next time the io_service object finds itself inside one of the run() or poll methods. Once it reaches the head of the queue, it will get popped, executed and destroyed.

int main(int argc, char* argv[]) {
    asio::io_service io_service;
    io_service.post([]() {
            std::cout << "Running async method" << std::endl;
        });
    io_service.run();
    return 0;
}

This is exactly how the completion handler argument of all the Asio classes’ async_ methods work. Typically one or more threads will create Asio objects that take an io_service in their constructor and one thread will call io_service::run(). An async operation is initiated by a method call that accepts a completion handler (ex: async_resolve) on one of these objects. Since the Asio objects all retain a reference to the io_service, once the async operation completes they will use the reference to queue their completion handler for execution.

We can see how this works in practice using the Asio basic_resolver class. Consider the case of a web crawler which retrieves a domain’s web pages for some back end process to index, analyze or archive. Before any pages can actually be fetched, the crawler must first resolve that domain name into an IP address. The Asio examples always show a synchronous call to resolve(), so we’ll improve upon that by going full async.

int main (int argc, char* argv[]) {
    asio::io_service io_service;
    asio::tcp::resolver r(io_service);

    r.async_resolve(
        asio::tcp::resolver::query("google.com", "http"),
        [](const boost::system::error_code& ec,
           asio::tcp::resolver::iterator it) {
            std::cout << it->endpoint() << std::endl;
        });

    io_service.run();
    return 0;
}

Full source code is always available on my GitHub repo.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s