2014-03-31 40 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