使用libevent异步解析dns

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开发入门》。

下面是所有代码:

[cpp] view plaincopy

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

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

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

时间: 2024-08-09 21:29:55

使用libevent异步解析dns的相关文章

【iOS】异步解析dns

发现iOS封装的有点恶心,把select封装成了CFRunLoop的形式,又把CFRunLoop封装成了NSRunLoop,跟select使用方式又一样了. 又弄一些玄之又玄的概念,AF_UNIX封装成了NSPort.项目中遇到了需要异步解析dns的问题,需要解析dns的时候,另一个线程去取消它,但又不能单单的起一个线程,然后强制结束. 这样的退出是不优雅的. 最后自己用C写了一个dns协议… 想整合到socket跨平台框架中, 后来又发现我没有办法获取dhcp获得的dns服务器地址.最后只能在

Apache Commons Digester 二(规则模块绑定-RulesModule、异步解析-asyncParse、xml变量Substitutor、带参构造方法)

前言 上一篇对Digester做了基本介绍,也已经了解了Digester的基本使用方法,接下来将继续学习其相关特性,本篇主要涉及以下几个内容: 规则模块绑定,通过定义一个RulesModule接口实现类来完成规则的预先绑定,运行时重复使用 异步解析xml 解析xml中的变量,如${sys.user} 使用带参数的构造方法创建对象,参数来自xml节点数据 规则模块预先绑定 - RulesModule接口 在此之前,我们使用Digester的基本流程都是每次在程序运行时绑定规则,然后解析: 事实上,

win8不能解析DNS导致不能访问外网问题

win8不能解析DNS导致不能访问外网问题 win8系统以前都可以正常上网,早上发现不能访问外网问题,内网可以访问.找运维同事查看后,发现是DNS不能解析问题,这个问题可能是win8自身的bug,也可能是安装其它软件时不小心造成的.具体解决方法如下: 1 将用户切换为Administrator用户,即管理员用户.如果管理员用户被禁用,通过以下步骤操作: 然后切换至管理员账户,通过管理员账户进入win8系统. 2 重置DNS服务器 重置后即可正常上网了.

javascript 异步解析

js 异步解析 一 .js单线程分析 我们都知道js的一大特点是单线程,也就是同一时间点,只能处理一件事,一句js代码.那为什么js要设计成单线程而不是多线程呢?这主要和js的用途有关,js作为浏览器端的脚本语言,主要的用途为用户与服务端的交互与操作dom.而操作dom就注定了js只能是单线程语言.假如js才取多线程将会出现,多个线程同时对一个dom进行操作的情况,浏览器将无法判断如何渲染.不仅js是单线程,浏览器渲染dom也是单线程的,js的执行和浏览器渲染dom共用的一个线程,这就导致了在h

智能NDS服务器的搭建——三大运营商线路分流解析DNS

在我们中国电信运营商不止一家,有电信.移动.网通,但我们在访问互联网资源时,有时候就会现跨网访问的情况,但有时间跨网访问速度是奇慢的.所以我们的网站运营商,也会在网站的服务器上同时配上三大电信运营商的线路,如此一来,电信用户访问的时候就走电信的出口,移动用户访问的时候就走移动的出口,网通通用户访问的就走网通的出口,这样也就很好的解决了跨网访问速度奇慢的问题的了.但这里其实就用到了,如何让DNS在解析地址的过程中智能的去判断哪个运营商的用户走哪条线路了.今天在这里给大家模拟实现一下,智能DNS如何

Linux 下用 Bind9 搭建智能解析 DNS 服务器手记

根据百度出来的感谢各位前辈大神的文章指导,费了一下午时间,自己的智能解析平台搭建完成.平台CentOS6.6,软件系统自带的Bind9: [[email protected] ~]# named -v BIND 9.8.2rc1-RedHat-9.8.2-0.30.rc1.el6_6.1 named.conf配置如下: options { //listen-on port 53 { 127.0.0.1; }; //listen-on-v6 port 53 { ::1; }; directory

iOS学习 - 22 异步解析 JSON,使用 Model 存储,TableView 显示

Model 类: @interface ListModel : NSObject @property (nonatomic, copy)NSString *time; @property (nonatomic, copy)NSString *cname; @property (nonatomic, copy)NSString *summary; @property (nonatomic, copy)NSString *title; @property (nonatomic, copy)NSStr

Python解析DNS数据包

工作中有时需要对DNS数据包进行解析,抽取出其中的Qurey Name和Answer中的IP地址,今天写了一个简单的脚本分析PCAP包中的DNS,用到了dpkt模块. 我只抽取了关键的Query Name和Answer中的IP地址,没有解析授权和额外信息. 如果不想写脚本,可以使用tshark工具(wireshark的命令行版本),使用简单的命令行即可抽取想要的信息.但是tshark在抽取IP地址的时候,会将授权域和额外域中的IP地址也会一起抽取出来,难以区分. 1 #!/usr/bin/pyt

DNS BIND配置 配置基本缓存服务器 DNS正向解析 DNS反向解析

一. 缓存服务器配置 1.DNS:BIND    Berkeley Internet Name Domain    版本bind97: RPM服务器端包的名字  安装bind-libs    bind-utils    配置文件 /etc/named.conf        BIND进程的工作属性        区域的定义     rndc: Remote Name Domain Controller        密钥文件 /etc/rndc.key        配置信息:/etc/rndc