【Asio】DNS域名解析

(点击上方公众号,可快速关注)

背景

互联网应用是通过IP标识通信双方的主机地址的。常用的IPv4是32位的整数,而这个数字不好记忆,所以引入了更加适合人类阅读和记忆的点分十进制表示法,如环回地址对应“127.0.0.1“。即使这样,本质上还是数字,仍然不利于沟通和记忆,试想以下,每次访问网站都要输入这样的地址,我们要记忆一大推这样的无意义的数字,抑或是随身带着一个笔记本,专门用来IP地址,这是多么不方便。

为了解决上面的问题,引入了域名(Domain Name)。域名可以看作是一个有意义的字符串和IP列表的映射。在通信过程中,先根据域名找到IP地址,之后的通信使用IP地址进行。将域名解析为IP地址的过程,就是域名解析。要实现域名解析,需要还需要两方面的支持:

  1. 映射存在何处

    难不成每台电脑都保存千千万万的映射?当然不是。这些映射保存在DNS(Domain Name System)。全世界部署着很多DNS服务器节点,每次域名解析会根据规则请求这些DNS节点得到对应的IP地址。

  2. 解析函数

    通常每个操作系统都提供相应的接口用于域名解析,如在Linux下是gethostbyname函数,ASIO底层使用该函数进行域名解析。

除了上面可读性的差异外,域名还提供了高可用的保障:一个域名可以对应多个IP地址,如果某个IP地址上的主机宕了,可以使用另外的IP进行通信。而且,也利于系统的平滑升级:若客户端和服务端通过通信,服务端升级到新机器,只要域名指向新机器,客户端不需要做改动。

由于IPv6的逐渐流行,实际解析的地址可能既包含老的IPv4地址,又包含IPv6地址,这点需要注意。下面给出域名解析的示例。

UDP域名解析

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


using namespace boost;


int main()
{
    // 这里解析baidu的域名
  std::string host = "www.baidu.com";
  std::string port_num = "80";


  asio::io_context ioc;
    // 这步创建解析器
  asio::ip::udp::resolver resolver(ioc);


  boost::system::error_code ec;
  asio::ip::udp::resolver::results_type results = resolver.resolve(host, port_num, ec);


  if (ec.value() != 0) {
    std::cout << "Failed to resolve a DNS name."
      << "Error code = " << ec.value()
      << ". Message = " << ec.message();


    return ec.value();
  }


    // 打印IP地址
  for (auto it = results.cbegin(); it != results.cend(); ++it) {
    asio::ip::udp::endpoint const& ep = it->endpoint();
        std::cout << ep << std::endl;
  }


  return 0;
}

上面的示例调用asio::ip::udp::resolverresolve方法,得到asio::ip::udp::resolver::results_type类型的结果。asio::ip::udp::resolver::results_type本质上是个迭代器,可以通过迭代器的操作遍历。后面的循环打印每个endpoint。

这是程序调用的结果,包含IPv4和IPv6类型。

220.181.38.149:80
220.181.38.150:80
[240e:83:205:59:0:ff:b09b:159e]:80
[240e:83:205:58:0:ff:b09f:36bf]:80

上面的例子中有些类型是可以让编译器推断出的,之所以写出来是为了让类型明确出来。下面的TCP解析示例会使用auto替代一些冗长的类型。

TCP域名解析

udp版本完全一致,我们唯一要做的就是将asio::ip::udp::resolver改为asio::ip::tcp::resolver类型。

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


using namespace boost;


int main()
{
  std::string host = "www.baidu.com";
  std::string port_num = "80";


  asio::io_context ioc;
  asio::ip::tcp::resolver resolver(ioc);




  boost::system::error_code ec;
  auto results = resolver.resolve(host, port_num, ec);


  if (ec.value() != 0) {
    std::cout << "Failed to resolve a DNS name."
      << "Error code = " << ec.value()
      << ". Message = " << ec.message();


    return ec.value();
  }


  for (auto it = results.cbegin(); it != results.cend(); ++it) {
    auto const& ep = it->endpoint();
        std::cout << ep << std::endl;
  }


  return 0;
}
喜欢我的文章,请关注我的公众号。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值