Подтвердить что ты не робот

Портативный способ обнаружения различной сетевой ошибки в 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 с португальским языком по умолчанию.

[EDIT]

Я нашел способ сделать это, используя 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]

Обновлен после ответа 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")
    }
  }
}
4b9b3361

Ответ 1

Пакет net работает в тесном взаимодействии с вашей ОС. Для ошибок ОС в библиотеке Go std используется pkg syscall. Посмотрите здесь: http://golang.org/pkg/syscall/

Пакет net также может возвращать ошибки типа syscall.Errno.

Для более простого кода в вашей функции checkErr вы можете использовать переключатель типа (http://golang.org/doc/effective_go.html#type_switch).