Hostname resolvers

129

Usually we use a hostname to identify a remote server. However to connect to a server we need to know its IP address. To find out what IP address lies behind a particular hostname we should resolve it. There are different physical entities which can translate a given hostname into an IP address: remote DNS server, your router, /etc/hosts file, NETBIOS service, OS DNS cache. However you shouldn't really bother yourself on that since the API we will use to do that is all the same.

A class used to resolve hostnames into IP addresses is boost::asio::ip::tcp::resolver. The main function we need is resolver::resolve or resolver::async_resolve.

There can be multiple IP addresses behind the same hostname. You can pick any of them. This is a sort of simple load balancing. In the example below we will resolve google.com hostname and output the results into stdout:

#include <iostream>
#include <boost/asio.hpp>

namespace io = boost::asio;
namespace ip = io::ip;
using tcp = ip::tcp;
using error_code = boost::system::error_code;

int main()
{
    io::io_context io_context;
    error_code error;
    tcp::resolver resolver(io_context);

    tcp::resolver::results_type results = resolver.resolve("google.com", "80", error);

    for(tcp::endpoint const& endpoint : results)
    {
        std::cout << endpoint << "\n";
    }

    return 0;
}

If everything is correct then you should see something like this in the terminal window:

64.233.161.100:80
64.233.161.139:80
64.233.161.138:80
64.233.161.101:80
64.233.161.102:80
64.233.161.113:80

Resolving a hostname in an asynchronous manner would look like that:

resolver.async_resolve("google.com", "80", [&] (error_code error, tcp::resolver::results_type results)
{
    if(!error)
    {
        for(tcp::endpoint const& endpoint : results)
        {
            std::cout << endpoint << "\n";
        }
    }
    else
    {
        std::cerr << "Something went wrong";
    }
});

Several things we should mention:

Both resolver and endpoint classes are located inside tcp class scope. There are also udp::resolver, udp::endpoint, icmp::resolver and icmp::endpoint classes. However it doesn't really matter what protocol are you going to deal with — TCP, UDP or ICMP. Hostname resolution is all the same, as well as endpoints (which are just pairs of IP address and port). However Boost.Asio has a generalized and extensible architecture design, and it is assumed that different protocols may operate on types that may differ internally. Endpoint is a higher-level abstraction and it's not necessary consists of IP address and port (in general). So, to keep things nice you should use the same scope when you deal with the same protocol: use tcp::resolver::resolve to obtain tcp::endpoint and pass it into tcp::socket::connect. Same for udp and icmp. Even if you've came from plain C and such a separation doesn't make sense to you.

Take a look at the first two arguments of resolver::resolve. The first one is a hostname which we want to resolve: google.com — and that's kinda obvious. The second one is a port or a service name. In fact you don't need a port to resolve a hostname into an IP address. However since resolver::resolve returns an instance of endpoint class which is a pair of address and port, it needs a port to put it into the endpoint instance. You can pass an empty string as a second argument and this will work fine — in that case port value of the returned endpoint will be set to 0.

Some ports has string aliases (which are called “services”). So, if you don't want to hardcode port values, you can write one of those aliases instead:

tcp::resolver::results_type results = resolver.resolve("google.com", "http", error);

Full list of services is configured in the OS and can be found at:

  • /etc/services on Linux and Unix family systems;
  • %WINDIR%\System32\drivers\etc\services on Windows family systems.
Share this page:

Learning plan

A special execution model with a custom load balancer
14. Timers
Working with asynchronous timers within io_context polling loop
What's the difference between a client and a server, and what do they have in common
16. Hostname resolvers
Resolving hostnames into IP addresses before connect
Writing a very simple client application in C++ with Boost.Asio
How to deal with completion handlers manually to combine Boost.Asio with other APIs
Let's take a break and briefly look across everything we've learned so far