2014-03-31 37 views
11

我想确定网络级别发生了哪种错误。我发现的唯一方法是使用正则表达式检查错误消息,但是现在我发现这些消息可以使用不同的语言(取决于操作系统配置),从而难以通过正则表达式进行检测。有没有更好的方法来做到这一点?便携式检测Golang中的各种网络错误

package main 

import (
    "github.com/miekg/dns" 
    "net" 
    "regexp" 
) 

func main() { 
    var c dns.Client 
    m := new(dns.Msg) 

    m.SetQuestion("3com.br.", dns.TypeSOA) 
    _, _, err := c.Exchange(m, "ns1.3com.com.:53") 
    checkErr(err) 

    m.SetQuestion("example.com.", dns.TypeSOA) 
    _, _, err = c.Exchange(m, "idontexist.br.:53") 
    checkErr(err) 

    m.SetQuestion("acasadocartaocuritiba.blog.br.", dns.TypeSOA) 
    _, _, err = c.Exchange(m, "ns7.storedns22.in.:53") 
    checkErr(err) 
} 

func checkErr(err error) { 
    if err == nil { 
    println("Ok") 
    } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() { 
    println("Timeout") 
    } else if match, _ := regexp.MatchString(".*lookup.*", err.Error()); match { 
    println("Unknown host") 
    } else if match, _ := regexp.MatchString(".*connection refused.*", err.Error()); match { 
    println("Connection refused") 
    } else { 
    println("Other error") 
    } 
} 

结果:

$ go run neterrors.go 
Timeout 
Unknown host 
Connection refused 

我为默认语言的Windows操作系统与葡萄牙的测试系统时发现的问题。

[编辑]

我找到了一种方法使用OpError做到这一点。新方法再次使用checkErr函数。如果有人有更好的解决方案,我会很高兴知道它!

func checkErr(err error) { 
    if err == nil { 
    println("Ok") 
    } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() { 
    println("Timeout") 
    } else if opError, ok := err.(*net.OpError); ok { 
    if opError.Op == "dial" { 
     println("Unknown host") 
    } else if opError.Op == "read" { 
     println("Connection refused") 
    } 
    } 
} 

[EDIT2]

洪城答案后更新。

func checkErr(err error) { 
    if err == nil { 
    println("Ok") 
    return 

    } else if netError, ok := err.(net.Error); ok && netError.Timeout() { 
    println("Timeout") 
    return 
    } 

    switch t := err.(type) { 
    case *net.OpError: 
    if t.Op == "dial" { 
     println("Unknown host") 
    } else if t.Op == "read" { 
     println("Connection refused") 
    } 

    case syscall.Errno: 
    if t == syscall.ECONNREFUSED { 
     println("Connection refused") 
    } 
    } 
} 
+4

go1.6返回'* os.SyscallError'而不是'syscall.Errno' –

回答

2

net软件包与您的操作系统密切合作。对于操作系统错误,Go std库使用pkg syscall。看看这里:http://golang.org/pkg/syscall/

net包还可以返回syscall.Errno类型的错误。

对于简单的代码checkErr函数,可以考虑使用类型开关(http://golang.org/doc/effective_go.html#type_switch)。

+0

go'syscall'包不可移植;它取决于操作系统。 Go'os'包与操作系统无关。 [“Package syscall包含低级操作系统原语的接口,具体细节取决于底层系统”](http://golang.org/pkg/syscall/) – peterSO

+0

Woops,你是绝对正确的。我正在看错误的pkg。 – seong

+1

我改变了相应的答案。 'net'软件包可能会返回'syscall.Errno'错误,但细节确实会因操作系统而异。 – seong