How does Boost Asio's hostname resolution work

2020-06-16 05:28发布

问题:

I'm attempting to make my networked application work locally (with both the server and client running on the same computer) when there is no network connection. This seems to "just work" occasionally, but most of the time I end up with:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'
       what(): Host not found (authoritative)
    Aborted

The code I'm currently using is:

  tcp::resolver::query query(host, PORT);
  tcp::resolver::iterator endpointIterator = resolver.resolve(query);
  tcp::resolver::iterator end;

  boost::system::error_code error = boost::asio::error::host_not_found;
  while(error && endpointIterator != end)
  {
    mySocket.close();
    mySocket.connect(*endpointIterator++, error);
  }
  if(error)
    throw boost::system::system_error(error);

I'm pretty sure I've narrow the problem down to ip::basic_resolver::resolve, but I can't figure out how that's implemented on Linux or what else I might want to use. This seems to be the same issue. It seems that just not performing any lookup at all and just using 127.0.0.1 should work, but when I tried replacing the query line with

tcp::resolver::query query(host, PORT, boost::asio::ip::resolver_query_base::address_configured | boost::asio::ip::resolver_query_base::numeric_host

it didnt' work. As I was writing this I found my mistake, the address_configured flag (which is set by default) prevents resolve from returning if the loopback device is the only one with an address. I'm still posting this question in the hopes that it helps someone else, but I've solved my issue.

Now I use

tcp::resolver::query query(host, PORT, boost::asio::ip::resolver_query_base::numeric_service);

Though other people might not want the flag I'm using if they do want to lookup service names (I'm just using port numbers).

回答1:

The problem was that the constructor for query has the address_configured flag set by default which won't return an address if the loopback device is the only device with an address. By just settings flags to 0 or anything other than address_configured the problem is fixed. Here is what I'm successfully using now:

tcp::resolver::query query(host, PORT, boost::asio::ip::resolver_query_base::numeric_service);

Hope this helps anyone with this problem in the future.



回答2:

The constructor for query defaults to having the flag "address_configured".

ip::basic_resolver_query::address_configured

Only return IPv4 addresses if a non-loopback IPv4 address is configured for the system. Only return IPv6 addresses if a non-loopback IPv6 address is configured for the system.

While setting the flag to something else will work, it will also have the side effects of said flag. To avoid this use the "default" of the enum.

tcp::resolver::query query(host, PORT, boost::asio::ip::resolver_query_base::flags());

It used to be possible to just use 0, but the library has become more strict to prevent accidental use of an int as the service name.