码迷,mamicode.com
首页 > 其他好文 > 详细

使用libevent异步解析dns

时间:2014-11-23 07:01:03      阅读:312      评论:0      收藏:0      [点我收藏+]

标签:android   style   blog   http   io   ar   os   使用   sp   

  libevent 自带 dns 解析库,支持同步、异步两种方式解析域名。因 libevent 本身是异步事件驱动型类库,我们在基于它做应用时,也多数是使用异步模型,因此这里介绍一下如何使用 libevent 异步解析域名。 libevent 官网有文章专门介绍 DNS 功能,请参考《Using DNS with Libevent》。

    我这里的例子和官网稍有不同,主要体现在对 DNS 服务器的配置上,区分了多平台。因为我发现在 Android (安卓)平台上, libevent 在获取 DNS 服务器时有问题,具体请参考另一篇博文《libevent 在 Android 上的一个改进》。

    我使用 libevent-2.1.3-alpha (请到官网下载)和 Qt 5.2 。关于 Qt 环境搭建,参考《Windows下Qt 5.2 for Android开发入门》。

    下面是所有代码:

  1. struct event_base * g_evbase = 0;  
  2. struct evdns_base * g_dnsbase = 0;  
  3.   
  4. static void _dns_callback(int errcode, struct evutil_addrinfo *addr, void *ptr)  
  5. {  
  6.     if (errcode)  
  7.     {  
  8.         printf("%s -> %s\n", (char*)ptr, evutil_gai_strerror(errcode));  
  9.     }  
  10.     else  
  11.     {  
  12.         struct evutil_addrinfo *ai;  
  13.         char ip[128];  
  14.         printf("dns resolved,hostname - %s, ip :\n", (char*)ptr);  
  15.         for (ai = addr; ai; ai = ai->ai_next)  
  16.         {  
  17.             const char *s = NULL;  
  18.             if (ai->ai_family == AF_INET)  
  19.             {  
  20.                 struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;  
  21.                 s = evutil_inet_ntop(AF_INET, &sin->sin_addr, ip, 128);  
  22.             }  
  23.             else if (ai->ai_family == AF_INET6)  
  24.             {  
  25.                 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;  
  26.                 s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, ip, 128);  
  27.             }  
  28.             if(s)  
  29.             {  
  30.                 printf("  %s\n", s);  
  31.             }  
  32.         }  
  33.     }  
  34.   
  35.     if(addr)evutil_freeaddrinfo(addr);  
  36. }  
  37.   
  38.   
  39. struct evdns_base * setup_evdns_base(struct event_base *base)  
  40. {  
  41.     if(g_dnsbase)  
  42.     {  
  43.         return g_dnsbase;  
  44.     }  
  45.     else  
  46.     {  
  47.         struct evdns_base * dnsbase = 0;  
  48. #if defined(_WIN32)  
  49.         dnsbase = evdns_base_new(base, 0);  
  50.         evdns_base_nameserver_ip_add(dnsbase, "8.8.8.8");  
  51. #elif defined(ANDROID)  
  52.         dnsbase = evdns_base_new(base, 0);  
  53.         {  
  54.             int ret = 0;  
  55.             int contains_default = 0;  
  56.             char buf[PROP_VALUE_MAX];  
  57.             ret = __system_property_get("net.dns1", buf);  
  58.             if(ret >= 7)  
  59.             {  
  60.                 if(!strncmp("8.8.8.8", buf, 7)) contains_default = 1;  
  61.                 evdns_base_nameserver_ip_add(dnsbase, buf);  
  62.             }  
  63.             ret = __system_property_get("net.dns2", buf);  
  64.             if(ret >= 7)  
  65.             {  
  66.                 if(!strncmp("8.8.8.8", buf, 7)) contains_default = 1;  
  67.                 evdns_base_nameserver_ip_add(dnsbase, buf);  
  68.             }  
  69.             if(!contains_default)  
  70.             {  
  71.                 evdns_base_nameserver_ip_add(dnsbase, "8.8.8.8");  
  72.             }  
  73.         }  
  74. #else  
  75.         dnsbase = evdns_base_new(base, 1);  
  76. #endif  
  77.         printf(" dns server count : %d\n", evdns_base_count_nameservers(dnsbase));  
  78.   
  79.         g_dnsbase = dnsbase;  
  80.         return dnsbase;  
  81.     }  
  82. }  
  83.   
  84.   
  85. static int lookup_host(const char * host)  
  86. {  
  87.     struct evutil_addrinfo hints;  
  88.     struct evdns_getaddrinfo_request *req;  
  89.     memset(&hints, 0, sizeof(hints));  
  90.     hints.ai_family = AF_UNSPEC;  
  91.     hints.ai_flags = EVUTIL_AI_CANONNAME;  
  92.     hints.ai_socktype = SOCK_STREAM;  
  93.     hints.ai_protocol = IPPROTO_TCP;  
  94.   
  95.     req = evdns_getaddrinfo(g_dnsbase, host, NULL ,  
  96.                 &hints, _dns_callback, (void*)host);  
  97.     if (req == NULL)  
  98.     {  
  99.         printf("    [request for %s returned immediately]\n", host);  
  100.         return -1;  
  101.     }  
  102.     return 0;  
  103. }  
  104.   
  105.   
  106.   
  107. int main(int argc, char **argv)  
  108. {  
  109. #ifdef WIN32  
  110.     WORD wVersionRequested;  
  111.     WSADATA wsaData;  
  112.   
  113.     wVersionRequested = MAKEWORD(2, 2);  
  114.   
  115.     (void) WSAStartup(wVersionRequested, &wsaData);  
  116. #endif  
  117.   
  118.     if(argc < 2)  
  119.     {  
  120.         printf("Usage: \n    dns_resolv hostname\n");  
  121.         return 0;  
  122.     }  
  123.   
  124.     g_evbase = event_base_new();  
  125.     setup_evdns_base(g_evbase);  
  126.     if(lookup_host(argv[1]) == 0)  
  127.     {  
  128.         event_base_loop(g_evbase, EVLOOP_NO_EXIT_ON_EMPTY);  
  129.     }  
  130.   
  131.     event_base_free(g_evbase);  
  132.     evdns_base_free(g_dnsbase, 1);  
  133.   
  134. #ifdef WIN32  
  135.     (void) WSACleanup();  
  136. #endif  
  137.     return 0;  
  138. }  


    代码比较简单,从命令行获取待解析域名进行解析。通过 WIN32 ,ANDROID 这样一些宏来区分不同平台。

    需要说明一点,在我的 Win7 环境下,通过 evdns_base_new(base, 1) 这种方式无法读取到域名服务器,所以我配置了 google 的 8.8.8.8 来使用。

使用libevent异步解析dns

标签:android   style   blog   http   io   ar   os   使用   sp   

原文地址:http://www.cnblogs.com/yuyanbian/p/4116094.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!