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

Error handling 检测不同类型网络错误的便携式方法,error-handling,network-programming,go,Error Handling,Network Programming,Go,我想确定在网络级别发生了什么样的错误。我发现的唯一方法是使用正则表达式检查错误消息,但现在我发现这些消息可以使用不同的语言(取决于操作系统配置),这使得正则表达式很难检测到。有更好的方法吗 package main import ( "github.com/miekg/dns" "net" "regexp" ) func main() { var c dns.Client m := new(dns.Msg) m.SetQuestion("3com.br.", dns

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

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操作系统中测试系统时,我发现了这个问题

[编辑]

我找到了一种使用Operor的方法。下面是使用新方法的checker函数。如果有人有更好的解决方案,我会很高兴知道它

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")
    }
  }
}

net
软件包与您的操作系统紧密配合。对于操作系统错误,Go std库使用pkg
syscall
。请看这里:


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


在您的代码> CuxKrr < /C>函数中,您可以考虑使用类型开关().< /P>:GO <代码> SysCals包不是可移植的;这取决于操作系统。Go

os
包独立于操作系统。呜呜,你完全正确。我看错了包装。我相应地改变了答案。
net
程序包可以返回
syscall.Errno
错误,但是细节确实会因您的操作系统而异。太棒了!返回的错误始终实现net.error和*net.OpError结构,在net.OpError结构中,我们有一个可以是syscall.Errno的内部错误。对于这种情况,我仍然需要检查Windows操作系统上返回的errno值。对于Linux,由于连接被拒绝,我们得到了ECONREFUNCE。但是当我们有一个“未知主机”或超时情况时,没有定义Errno(对于超时,明显的选择是ETIMEDOUT)。go1.6返回
*os.SyscallError
而不是
syscall。Errno
t.Op==“拨号”也可以与MacOS上go 1.16.3的“拒绝连接”相关联。