检测不同类型网络错误的便携方法

huangapple go评论121阅读模式
英文:

Portable way to detect different kinds of network error

问题

我想要确定网络层发生了什么样的错误。我找到的唯一方法是使用正则表达式检查错误消息,但现在我发现这些消息可能是不同的语言(取决于操作系统配置),这使得通过正则表达式难以检测。有没有更好的方法来做到这一点?

  1. package main
  2. import (
  3. "github.com/miekg/dns"
  4. "net"
  5. "regexp"
  6. )
  7. func main() {
  8. var c dns.Client
  9. m := new(dns.Msg)
  10. m.SetQuestion("3com.br.", dns.TypeSOA)
  11. _, _, err := c.Exchange(m, "ns1.3com.com.:53")
  12. checkErr(err)
  13. m.SetQuestion("example.com.", dns.TypeSOA)
  14. _, _, err = c.Exchange(m, "idontexist.br.:53")
  15. checkErr(err)
  16. m.SetQuestion("acasadocartaocuritiba.blog.br.", dns.TypeSOA)
  17. _, _, err = c.Exchange(m, "ns7.storedns22.in.:53")
  18. checkErr(err)
  19. }
  20. func checkErr(err error) {
  21. if err == nil {
  22. println("Ok")
  23. } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
  24. println("Timeout")
  25. } else if match, _ := regexp.MatchString(".*lookup.*", err.Error()); match {
  26. println("Unknown host")
  27. } else if match, _ := regexp.MatchString(".*connection refused.*", err.Error()); match {
  28. println("Connection refused")
  29. } else {
  30. println("Other error")
  31. }
  32. }

结果:

  1. $ go run neterrors.go
  2. Timeout
  3. Unknown host
  4. Connection refused

我在使用葡萄牙语作为默认语言的 Windows 操作系统中测试系统时发现了这个问题。

[编辑]

我找到了一种使用 OpError 的方法。这是带有新方法的 checkErr 函数。如果有人有更好的解决方案,我将非常乐意了解!

  1. func checkErr(err error) {
  2. if err == nil {
  3. println("Ok")
  4. } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
  5. println("Timeout")
  6. } else if opError, ok := err.(*net.OpError); ok {
  7. if opError.Op == "dial" {
  8. println("Unknown host")
  9. } else if opError.Op == "read" {
  10. println("Connection refused")
  11. }
  12. }
  13. }

[编辑2]

根据 seong 的回答进行了更新。

  1. func checkErr(err error) {
  2. if err == nil {
  3. println("Ok")
  4. return
  5. } else if netError, ok := err.(net.Error); ok && netError.Timeout() {
  6. println("Timeout")
  7. return
  8. }
  9. switch t := err.(type) {
  10. case *net.OpError:
  11. if t.Op == "dial" {
  12. println("Unknown host")
  13. } else if t.Op == "read" {
  14. println("Connection refused")
  15. }
  16. case syscall.Errno:
  17. if t == syscall.ECONNREFUSED {
  18. println("Connection refused")
  19. }
  20. }
  21. }
英文:

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?

  1. package main
  2. import (
  3. "github.com/miekg/dns"
  4. "net"
  5. "regexp"
  6. )
  7. func main() {
  8. var c dns.Client
  9. m := new(dns.Msg)
  10. m.SetQuestion("3com.br.", dns.TypeSOA)
  11. _, _, err := c.Exchange(m, "ns1.3com.com.:53")
  12. checkErr(err)
  13. m.SetQuestion("example.com.", dns.TypeSOA)
  14. _, _, err = c.Exchange(m, "idontexist.br.:53")
  15. checkErr(err)
  16. m.SetQuestion("acasadocartaocuritiba.blog.br.", dns.TypeSOA)
  17. _, _, err = c.Exchange(m, "ns7.storedns22.in.:53")
  18. checkErr(err)
  19. }
  20. func checkErr(err error) {
  21. if err == nil {
  22. println("Ok")
  23. } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
  24. println("Timeout")
  25. } else if match, _ := regexp.MatchString(".*lookup.*", err.Error()); match {
  26. println("Unknown host")
  27. } else if match, _ := regexp.MatchString(".*connection refused.*", err.Error()); match {
  28. println("Connection refused")
  29. } else {
  30. println("Other error")
  31. }
  32. }

Result:

  1. $ go run neterrors.go
  2. Timeout
  3. Unknown host
  4. 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!

  1. func checkErr(err error) {
  2. if err == nil {
  3. println("Ok")
  4. } else if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
  5. println("Timeout")
  6. } else if opError, ok := err.(*net.OpError); ok {
  7. if opError.Op == "dial" {
  8. println("Unknown host")
  9. } else if opError.Op == "read" {
  10. println("Connection refused")
  11. }
  12. }
  13. }

[EDIT2]

Updated after seong answer.

  1. func checkErr(err error) {
  2. if err == nil {
  3. println("Ok")
  4. return
  5. } else if netError, ok := err.(net.Error); ok && netError.Timeout() {
  6. println("Timeout")
  7. return
  8. }
  9. switch t := err.(type) {
  10. case *net.OpError:
  11. if t.Op == "dial" {
  12. println("Unknown host")
  13. } else if t.Op == "read" {
  14. println("Connection refused")
  15. }
  16. case syscall.Errno:
  17. if t == syscall.ECONNREFUSED {
  18. println("Connection refused")
  19. }
  20. }
  21. }

答案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).

huangapple
  • 本文由 发表于 2014年3月31日 20:29:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/22761562.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定