想在 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. mybatisplus的坑 insert标签insert into select无参数问题的解决
  2. Android(安卓)Studio在线调试Android(安卓)Framework Java代码
  3. Analyzing Android(安卓)Malware
  4. Android源代码下载
  5. android 关于Dialog 圆角的问题
  6. Android中解决手机屏幕横竖屏切换问题
  7. Android横屏竖屏切换的问题
  8. android onTouchEvent和setOnTouchListener中onTouch的区别
  9. Android(安卓)UI学习系列

随机推荐

  1. Android中的UI更新
  2. Android 迁移到 Androidx
  3. 基于Platinum库的DLNA开发
  4. Android HTTPS认证之Volley封装
  5. react-natvie vscode真机调试[Android]
  6. android避免弹出软键盘遮盖listview
  7. 【Android 界面效果6】Android 控件之Ima
  8. android数据库使用小结
  9. Android Binder驱动源码下载地址
  10. Android(安卓)开发值得订阅的日报和周刊