另一种解决Go编译的Linux程序在Android下无法解析DNS的方法

Go的一大优点就是编译出的程序完全静态,不依赖需要包括libc在内的任何动态库。因此只要所需syscall是正常的,一个GOOS=linux的纯Go程序可以行为一致地运行在一切Linux平台上...这当然也包括Android,对吧?

然而你可能很快会发现,你的程序在Android下运行并不那么正常——比如DNS解析。Go自带的DNS resolver实现是/etc/resolve.conf读取DNS服务器地址,但Android下并不存在这个文件。关于适配Android的问题其实很早就被提了出来,只是目前官方根本没有着手解决的意思。一种主流的解决方法是启用CGO,在编译时动态链接Android NDK中的libc,但这样相当于需要制作一个"Android专版",破坏了一个程序通用所有Linux的优雅性,再说为了解决一个DNS问题去配置一套NDK也有点小题大做。

既然这里的问题单纯只是Go默认的resolver无法在Android上获取DNS配置,那么就手动指定一个DNS好了...这里用的8.8.8.8

const dnsServerAddress = "8.8.8.8:53"

func dnsPatch() {
 http.DefaultTransport = &http.Transport{
  DialContext: (&net.Dialer{
   Timeout:   30 * time.Second,
   KeepAlive: 30 * time.Second,
   DualStack: true,
   Resolver: &net.Resolver{
    PreferGo: true,
    Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
     d := net.Dialer{}
     return d.DialContext(ctx, "udp", dnsServerAddress)
    },
   },
  }).DialContext,
  MaxIdleConns:          10,
  IdleConnTimeout:       90 * time.Second,
  TLSHandshakeTimeout:   10 * time.Second,
  ExpectContinueTimeout: 1 * time.Second,
 }
}

这里只替换了http中的DefaultTransport,请根据程序中涉及网络的实际情况判断是否需要进一步替换如net等包中的类似结构。

comments powered by Disqus