首页 > 代码库 > 使用libevent异步解析dns
使用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
- struct event_base * g_evbase = 0;
- struct evdns_base * g_dnsbase = 0;
- static void _dns_callback(int errcode, struct evutil_addrinfo *addr, void *ptr)
- {
- if (errcode)
- {
- printf("%s -> %s\n", (char*)ptr, evutil_gai_strerror(errcode));
- }
- else
- {
- struct evutil_addrinfo *ai;
- char ip[128];
- printf("dns resolved,hostname - %s, ip :\n", (char*)ptr);
- for (ai = addr; ai; ai = ai->ai_next)
- {
- const char *s = NULL;
- if (ai->ai_family == AF_INET)
- {
- struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
- s = evutil_inet_ntop(AF_INET, &sin->sin_addr, ip, 128);
- }
- else if (ai->ai_family == AF_INET6)
- {
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
- s = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, ip, 128);
- }
- if(s)
- {
- printf(" %s\n", s);
- }
- }
- }
- if(addr)evutil_freeaddrinfo(addr);
- }
- struct evdns_base * setup_evdns_base(struct event_base *base)
- {
- if(g_dnsbase)
- {
- return g_dnsbase;
- }
- else
- {
- struct evdns_base * dnsbase = 0;
- #if defined(_WIN32)
- dnsbase = evdns_base_new(base, 0);
- evdns_base_nameserver_ip_add(dnsbase, "8.8.8.8");
- #elif defined(ANDROID)
- dnsbase = evdns_base_new(base, 0);
- {
- int ret = 0;
- int contains_default = 0;
- char buf[PROP_VALUE_MAX];
- ret = __system_property_get("net.dns1", buf);
- if(ret >= 7)
- {
- if(!strncmp("8.8.8.8", buf, 7)) contains_default = 1;
- evdns_base_nameserver_ip_add(dnsbase, buf);
- }
- ret = __system_property_get("net.dns2", buf);
- if(ret >= 7)
- {
- if(!strncmp("8.8.8.8", buf, 7)) contains_default = 1;
- evdns_base_nameserver_ip_add(dnsbase, buf);
- }
- if(!contains_default)
- {
- evdns_base_nameserver_ip_add(dnsbase, "8.8.8.8");
- }
- }
- #else
- dnsbase = evdns_base_new(base, 1);
- #endif
- printf(" dns server count : %d\n", evdns_base_count_nameservers(dnsbase));
- g_dnsbase = dnsbase;
- return dnsbase;
- }
- }
- static int lookup_host(const char * host)
- {
- struct evutil_addrinfo hints;
- struct evdns_getaddrinfo_request *req;
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_flags = EVUTIL_AI_CANONNAME;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- req = evdns_getaddrinfo(g_dnsbase, host, NULL ,
- &hints, _dns_callback, (void*)host);
- if (req == NULL)
- {
- printf(" [request for %s returned immediately]\n", host);
- return -1;
- }
- return 0;
- }
- int main(int argc, char **argv)
- {
- #ifdef WIN32
- WORD wVersionRequested;
- WSADATA wsaData;
- wVersionRequested = MAKEWORD(2, 2);
- (void) WSAStartup(wVersionRequested, &wsaData);
- #endif
- if(argc < 2)
- {
- printf("Usage: \n dns_resolv hostname\n");
- return 0;
- }
- g_evbase = event_base_new();
- setup_evdns_base(g_evbase);
- if(lookup_host(argv[1]) == 0)
- {
- event_base_loop(g_evbase, EVLOOP_NO_EXIT_ON_EMPTY);
- }
- event_base_free(g_evbase);
- evdns_base_free(g_dnsbase, 1);
- #ifdef WIN32
- (void) WSACleanup();
- #endif
- return 0;
- }
代码比较简单,从命令行获取待解析域名进行解析。通过 WIN32 ,ANDROID 这样一些宏来区分不同平台。
需要说明一点,在我的 Win7 环境下,通过 evdns_base_new(base, 1) 这种方式无法读取到域名服务器,所以我配置了 google 的 8.8.8.8 来使用。
使用libevent异步解析dns
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。