Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493497
  • 博文数量: 25
  • 博客积分: 111
  • 博客等级: 民兵
  • 技术积分: 1279
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-26 20:51
文章分类

全部博文(25)

文章存档

2014年(17)

2013年(8)

分类: C/C++

2013-09-29 20:42:54

最近一直在看Boost Asio TCP相关的源码,今天对Resolver进行下总结。Resolver是Asio的域名解析系统,它将指定的URL和服务转化为相应的ip和port的endpoint端点。我们知道通过URL和服务获取相应IP和port的最简单方法是调用gethostby*和getservby*系列函数,然而这两个函数存在两个问题,首先gethostby*函数只能获取相应的 IPV4的信息,而不能获取IPV6的信息,这是因为IPV4与IPV6在DNS中的资源记录形式是不同,IPv4记录形式为A记录,而IPV6记录形式为AAAA记录,gethostby*函数在进行URL到IP查找时只查询A类型的记录,所以只查询IPV4,其次gethostby*和getservby*系列的函数是不可重入的,也就是说这些函数在多线程下是不安全的,因为在这些函数内部都调用并写同一个静态变量,然后将其返回。下面给出简要的代码:

点击(此处)折叠或打开

  1. static struct hostent host;

  2. struct hostent* gethostbyname(const char* host){
  3.       return (gethostbyname2(host,family));
  4. }

  5. struct hosten* gethostbyname2(const char* host,int family){
  6.       /*call DNS function for A or AAAA query*/
  7.       /*fill in host struct*/
  8.       return (&host);
  9. }

  10. struct host* gethostbyaddr(const char* addr,socklen_t len,int family){
  11.       /*call DNS function for PTR query int in-addr.arpa domain*/
  12.       /*fill in host struct*/
  13.       return(&host);
  14. }
注:上述代码来自unix网络编程11.18节。
通过上面代码,可以显然的看到两个函数共享同一个静态变量,而又没有加互斥操作,故是线程不安全的,也就是不可重入的。
为了解决上述两方面的问题,人们又引入了一个新函数getaddrinfo,此函数既可以查找URL对应的ipv4与ipv6,又能通过service或port查询相应的port或service,对此函数的具体介绍可以去看看unix网络编程,此处就不再赘述。我们所要说的asio的resolver就是在getaddrinfo的基础上编写出来的类。
resolver类只提供了一种构造函数:

点击(此处)折叠或打开

  1. explicit basic_resolver(boost::asio::io_service& io_service);
其中io_service相当于一个对象,替我们和OS打交道,并把结果返回给我们。上面代码的意思是我们定义一个resolver类,并把这个对象交给io_service叫它替我们管理。
此类提供了两种基于不同参数的解析函数以及它们的同步和异步版本,如下:

点击(此处)折叠或打开

  1. iterator resolve(const endpoint_type& e);
  2. iterator resolve(const query& q);
  3. void async_resolve(const endpoint_type& e,
  4.       BOOST_ASIO_MOVE_ARG(ResolveHandler) handler);
  5. void async_resolve(const query& q,
  6.       BOOST_ASIO_MOVE_ARG(ResolveHandler) handler)
下面对其进行简要说明:
首先endpoint_type是端点类型,它对IP和Port进行简要封装。query是对addrinfo_type结构的的封装,此处的addrinfo_type也就是原始结构addrinfo,我们在将addrinfo_type传给相应的resolve时,对其进行相应的设置,比如说仅仅查询IPV4版本的URL和服务或者仅仅只查询流套接字的服务,这些设置与源API并无二异,此处Asio仅仅只是对其进行简单的封装而已。此外与两个函数相对应的是其异步版本,其中回调函数必须是函数对象,我们可以通过boost bind(此处不是socket的那个bind)进行绑定。同步版本的返回值是一个endpoint类型的迭代器,也就是指针,它返回addrinfo_type结构中的ai_next链表结构中的第一个相应的endpoint类型也就是原始API的最后一个参数所对应的链表,我们可以通过++操作对此链表进行操作。
下面给出一个简单的实例:

点击(此处)折叠或打开

  1. boost::asio::io_service io_serv;
  2. boost::asio::ip::tcp::resolver::query q("","http");
  3. boost::asio::ip::tcp::resolver rslvr(io_serv);
  4. boost::asio::ip::tcp::resolver::iterator iter = rslvr.resolve(q);
  5. boost::asio::ip::tcp::resolver::iterator end;
  6. boost::asio::ip::tcp::endpoint point;
  7. while(iter != end){
  8.    point = *iter++;
  9.   std::cout<<point<<std::endl;
  10. }
此文出处:http://blog.chinaunix.net/uid-28311809-id-3928287.html



阅读(11086) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~