想在 Android 上使用 libevent 做一个下载程序,牵涉到域名解析的问题,发现 libevent 无法获取到 dns 服务器。研究了一下源码,找到了问题所在。
使用 libevent 的异步 dns 解析的一般过程如下:
- 调用evdns_base_new(struct event_base *event_base, int initialize_nameservers) 生成一个 evdns_base 对象
- 调用 evdns_getaddrinfo 并提供一个回调进行解析
- 在回调中处理结果
一般我们给 evdns_base_new 函数的第二个参数传递 1 以便 libevent 从系统配置中初始化 nameservers 。在 windows 上读取注册表,在 Linux 上读取 /etc/resolv.conf 。问题就出在这里,Android 上没有 resolv.conf 文件而 libevent 未做处理。查看 evdns.c 文件中的 evdns_base_new 函数实现可知:
struct evdns_base *
evdns_base_new(struct event_base *event_base, int initialize_nameservers)
{
struct evdns_base *base;
if (evutil_secure_rng_init() < 0) {
log(EVDNS_LOG_WARN, "Unable to seed random number generator; "
"DNS can't run.");
return NULL;
}
/* Give the evutil library a hook into its evdns-enabled
* functionality. We can't just call evdns_getaddrinfo directly or
* else libevent-core will depend on libevent-extras. */
evutil_set_evdns_getaddrinfo_fn(evdns_getaddrinfo);
base = mm_malloc(sizeof(struct evdns_base));
if (base == NULL)
return (NULL);
memset(base, 0, sizeof(struct evdns_base));
base->req_waiting_head = NULL;
EVTHREAD_ALLOC_LOCK(base->lock, EVTHREAD_LOCKTYPE_RECURSIVE);
EVDNS_LOCK(base);
/* Set max requests inflight and allocate req_heads. */
base->req_heads = NULL;
evdns_base_set_max_requests_inflight(base, 64);
base->server_head = NULL;
base->event_base = event_base;
base->global_good_nameservers = base->global_requests_inflight =
base->global_requests_waiting = 0;
base->global_timeout.tv_sec = 5;
base->global_timeout.tv_usec = 0;
base->global_max_reissues = 1;
base->global_max_retransmits = 3;
base->global_max_nameserver_timeout = 3;
base->global_search_state = NULL;
base->global_randomize_case = 1;
base->global_getaddrinfo_allow_skew.tv_sec = 3;
base->global_getaddrinfo_allow_skew.tv_usec = 0;
base->global_nameserver_probe_initial_timeout.tv_sec = 10;
base->global_nameserver_probe_initial_timeout.tv_usec = 0;
TAILQ_INIT(&base->hostsdb);
if (initialize_nameservers) {
int r;
#ifdef WIN32
r = evdns_base_config_windows_nameservers(base);
#else
r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
#endif
if (r == -1) {
evdns_base_free_and_unlock(base, 0);
return NULL;
}
}
EVDNS_UNLOCK(base);
return base;
}
就是 #ifdef WIN32 那几行代码。
解决方案是编译时增加一个 ANDROID 宏,针对 Android 平台实现读取 dns 配置的代码,这在我的文章《Android C 语言读取系统属性》中有相关解说。下面是具体的代码:
if (initialize_nameservers) {
int r;
#ifdef WIN32
r = evdns_base_config_windows_nameservers(base);
#elif defined(ANDROID)
{
int add_servers = 0;
char buf[PROP_VALUE_MAX];
r = __system_property_get("net.dns1", buf);
if(r >= 7)
{
add_servers++;
evdns_base_nameserver_ip_add(base, buf);
}
r = __system_property_get("net.dns2", buf);
if(r >= 7)
{
add_servers++;
evdns_base_nameserver_ip_add(base, buf);
}
if(add_servers == 0)
{
evdns_base_nameserver_ip_add(base,"8.8.8.8");
}
}
#else
r = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");
#endif
if (r == -1) {
evdns_base_free_and_unlock(base, 0);
return NULL;
}
}
OK ,现在可以正常工作了。
分享到:
相关推荐
libevent 在android上交叉编译脚本,支持各种系统架构
libevent for android 自己调试通过
Ubuntu下用NDK交叉编译的libevent库文件,对应的platforms使用android-14,gcc是采用arm-linux-androideabi-4.7
libevent-2.1.8-stable-android libevent_core.a libevent_extra.a
libevent在MFC上的实现, 花了1周的时间研究各种TCP模型, 包括LINUX和WINDOWS平台等, 包括C&C++, C#, JAVA, GOLANG, ERLANG等居于IOCP, SELECT, POLL, EPOLL, KQUEUE, BIO, NIO, AIO, 并发语言等实现的同步或异步...
c++版本libevent,仿照libevent写的一个服务器框架,libevent的基本功能已实现,暂时不能在windows平台上使用,定时器是纯粹的timer wheel方式,与libevent的小根堆不一样,而且最大定时时间是固定的,暂时不支持...
libevent-2.0.22-stable.tar.gz源码编译的Windows和Linux下的静态库,另附源码,电子书《libevent参考手册(中文版).pdf》、《libevent源码深度剖析.pdf》、《LibeventBook.pdf》。 Linux环境下该libevent静态库修改...
里面有教你如何在VS上配置libevent库,并配好后有个小例子可以感受下哦。
包含源码和编译结果。 如果要使用openssl 参考:http://download.csdn.net/detail/sos995/6397529
可移植性:使用 libevent 编写的程序应该可以在 libevent 支持的所有平台上工作。即使 没有好的方式进行非阻塞 IO,libevent 也应该支持一般的方式,让程序可以在受限的 环境中运行。 速度:libevent 尝试使用每个...
libevent2.1.7在Linux安装过程
libevent, 在https中,一个 public的libevent存储库 0.构建和安装( 简要) Autoconf $./configure $ make $ make verify # (optional) $ sudo make install
基于libevent的一个服务端和客户端,希望给新手学习参考一下
在实现上主要有3种链表: EVLIST_INSERTED, EVLIST_ACTIVE, EVLIST_TIMEOUT,一个ev在这3种链表之间被插入或删除,处于EVLIST_ACTIVE链表中的ev最后将会被调度执行。 Libevent提供了DNS,HTTP Server,RPC等组件,...
在linux下C语言通过libevent操作串口,通过libevent来实现回调读取串口数据。全部C代码,可直接编译和测试。
libevent参考手册(中文版),包含libevent的设计说明、原理描述,模块介绍和接口说明。
在实现上主要有3种链表: EVLIST_INSERTED, EVLIST_ACTIVE, EVLIST_TIMEOUT,一个ev在这3种链表之间被插入或删除,处于EVLIST_ACTIVE链表中的ev最后将会被调度执行。 Libevent提供了DNS,HTTP Server,RPC等组件,...
该资源为已经编译好的libevent静态库以及头文件,编译环境为win10 VS2017,对于该库的使用,创建http https server可参考本账号博客文章。
VS2015编译后的libevent头文件和库文件——基于libevent-2.1.10