Android NDK层发起 HTTP 请求的问题及解决

事件的起因不说了,总之是需要实现一个 NDK 层的网络请求。为了多端适用,还是选择了 CodeTyphon 作为跨平台方案。关于 CodeTyphon 此处不述,感兴趣的可以直接去其官网查看(传送门)。

CodeTyphon 自带的 fcl-web 库可以直接完成对于 HTTP 请求的支持,虽然我很想这么说... 在实际使用中,的确可以通过引入 fcl-web 来完成跨平台的网络请求,然而在 Android 端实际测试时,却发生了奇怪的错误。

比如说请求我自己的服务器 www.rarnu.com,会发生以下错误:

Error resolving host www.rarnu.com (-1)

而当我换用 IP 地址来请求时,却是可以成功的。

输入的域名是实际存在的,可以排除掉域名本身的问题。而使用 adb shell 连入设备,并使用 ping 命令访问该域名,也是正常的。

那么问题可能就出在,找不到 nameserver。我们都知道,在 Linux 下,nameserverresolv.conf 决定,这个文件通常保存在 /etc 下。于是看了一下,Android 里并没有这个文件,应该就是这个原因引起的了,因为读不到 resolv.conf 所以才导致了无法解释域名。接下来就是去找 Android 下,原本该是 resolv.conf 的东西保存在哪里。

不卖关子了,其实 Android 很早就把 resolv.conf 的内容改成了 key-value 的形式,采用 SystemProperties 进行存储,而其关键的 key 是 net.dns1net.dns2

尝试使用 adb 连接手机,并对以上两个 key 进行取值:

$ adb shell
$ getprop net.dns1
$ 208.67.222.222
$ getprop net.dns2
$ 208.67.220.220

我的手机上取出来的是 OpenDNS 的值,自己设置过。好了,既然已经知道了 nameserver 的所在,接下去就是修改代码以使程序识别和加载。


在 CodeTyphon 中,有一个基础库文件叫 netdb.pp,其中包含了 resolveName 方法,其具体代码如下:

function resolveName(hostName : String; var addresses : array of THostAddr) : Integer;
var
  i : Integer;
begin
  checkResolveFile;
  i := 0;
  result := 0;
  while (result <= 0) and (i <= high(DNSServers)) do begin
    result:=resolveNameAt(i, hostName, addresses,0);
    Inc(i);
  end;
end;

其实这段代码很明确,关键变量是 DNSServers,打印一下看看是个什么值:

writeLn(Format('DNSServer => %d', [high(DNSServers)]));

程序执行后打出来 -1,也就是说在 Android 下,由于 DNSServers 变量中没有任何的数据,导致了完全无法解析域名,在其他平台下,在此处打日志均显示 0,表示在这个数组里有一个下标为 0 的数据。

那事情就变得简单了,我们可以直接去找加载了 DNSServers 的地方,很容易的,找到了 InitResolver函数,由于该函数比较长,此处只截取加载 DNSServer 的部分:

procedure InitResolver;
begin
    ... ...
    if fileExists(etcPath + resolveFile) then
        GetDNsservers(etcPath + resolveFile);
    ... ...
end;

没有比这更明确的了,就是去找有没有 /etc/resolv.conf 嘛,找到就加载,没找到那就啥都不做了,而刚才说过了 Android 端并没有这么一个文件,于是直接就导致了 nameserver 缺失,间接引起域名无法解析。

好了,那么简易的解决方案也就有了,只需要重建 GetDNsservers 函数,使其能够适应 Android 端的情况即可。

下面给出代码:

function GetDNSServerAndroid(): Integer;
var
    L: string;
    H : THostAddr;
    E : THostEntry;
    function CheckDirective(Dir : String) : Boolean;
    var
        p : Integer;
    begin
        p := pos(Dir, L);
        result := p <> 0;
        If result then begin
            delete(L, 1, P + length(Dir));
            L := trim(L);
        end;
    end;
begin
    result := 0;
    L := 'nameserver ' + GetNetDNS();
    if StripComment(L) then begin
        If CheckDirective('nameserver') then begin
            H := HostToNet(StrToHostAddr(L));
            If (H.s_bytes[1] <> 0) then begin
                setlength(DNSServers, result + 1);
                DNSServers[result]:=H;
                Inc(result);
            end else if FindHostEntryInHostsFile(L, H, E) then begin
                setlength(DNSServers, result + 1);
                DNSServers[result]:=E.Addr;
                Inc(result);
            end;
        end;
    end;
end;

里面还有一个关键代码,是 GetNetDNS,它用于从 Android 内读取 net.dns1 变量:

function GetNetDNS(): String;
var
  outstr: string;
begin
  result := '';
  if (runCommand('getprop', ['net.dns1'], outstr, [poUsePipes, poWaitOnExit])) then
    result := outstr.Trim;
end;

最后,把上面的 InitResolver 改一下,使其可以正常加载工作于 Android 端的这段代码:

procedure InitResolver;
begin
    ... ...
    if fileExists(etcPath + resolveFile) then
        GetDNsservers(etcPath + resolveFile);
    {$IFDEF ANDROID}
        GetDNSServerAndroid();
    {$ENDIF}
    ... ...
end;

编译运行程序,Error resolving host 的问题即得到了解决。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280

推荐阅读更多精彩内容