想在 Android 上使用 libevent 做一个下载程序,牵涉到域名解析的问题,发现 libevent 无法获取到 dns 服务器。研究了一下源码,找到了问题所在。

使用 libevent 的异步 dns 解析的一般过程如下:

  1. 调用evdns_base_new(struct event_base *event_base, int initialize_nameservers) 生成一个 evdns_base 对象
  2. 调用 evdns_getaddrinfo 并提供一个回调进行解析
  3. 在回调中处理结果

一般我们给 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 WIN32r = evdns_base_config_windows_nameservers(base);#elser = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");#endifif (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 WIN32r = 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");        }    }#elser = evdns_base_resolv_conf_parse(base, DNS_OPTIONS_ALL, "/etc/resolv.conf");#endifif (r == -1) {evdns_base_free_and_unlock(base, 0);return NULL;}}

OK ,现在可以正常工作了。

更多相关文章

  1. Android Studio在线调试Android Framework Java代码
  2. Android 文件保存与读取
  3. 技巧: 如何安装apk文件在android仿真器中
  4. Android 根文件系统分析(1)
  5. [android] 保存文件到手机内存
  6. Android 将APK文件安装到AVD中并分析其界面结构
  7. 移动开发:fb的-app.xml文件
  8. Android源代码下载

随机推荐

  1. 【Android】SAX解析之错误纠正!!
  2. android获取SIM卡信息和手机号码
  3. Android通过SOAP协议和基于XFire实现的we
  4. IntelHaxm : 加速android模拟器启动速度(S
  5. MapView学习Demo2
  6. Kotlin Android(安卓)WebView与H5的相互
  7. android 比较靠谱的图片压缩
  8. android cts 命令的说明
  9. 执行Android JUnit测试出现java.net.Sock
  10. 用代码如何检测一个android程序是否在运