英文:
Portable way to detect different kinds of network error
问题
我想要确定网络层发生了什么样的错误。我找到的唯一方法是使用正则表达式检查错误消息,但现在我发现这些消息可能是不同的语言(取决于操作系统配置),这使得通过正则表达式难以检测。有没有更好的方法来做到这一点?
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")
}
}
}
[编辑2]
根据 seong 的回答进行了更新。
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")
}
}
}
英文:
I would like to identify what kind of error occurred in the network level. The only way I found was checking the error messages with a regular expression, but now I discovered that this messages can be in different languages (depending on the OS configuration), making it difficult to detect by regular expressions. Is there a better way to do it?
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")
}
}
Result:
$ go run neterrors.go
Timeout
Unknown host
Connection refused
I discover the problem when testing the system in a Windows OS with Portuguese as default language.
[EDIT]
I found a way to do it using the OpError. Here is the checkErr function again with the new approach. If someone has a better solution I will be very glad to known it!
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]
Updated after seong answer.
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")
}
}
}
答案1
得分: 8
net
包与您的操作系统密切配合。对于操作系统错误,Go标准库使用syscall
包。请参考这里:http://golang.org/pkg/syscall/
net
包还可以返回syscall.Errno
类型的错误。
对于您的checkErr
函数,您可以考虑使用类型开关语句来简化代码(http://golang.org/doc/effective_go.html#type_switch)。
英文:
The net
package works closely with your OS. For OS errors, the Go std library uses the pkg syscall
. Have a look here: http://golang.org/pkg/syscall/
The net
package can also return syscall.Errno
type errors.
For a simpler code in you checkErr
function, you could consider using a type switch (http://golang.org/doc/effective_go.html#type_switch).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论