Поймать "связать: адрес уже используется" в Голанге - PullRequest
0 голосов
/ 03 июля 2018

Я хочу отловить ошибку «bind: адрес уже используется» в golang.

conn, err := net.ListenUDP("udp", addr)
if err != nil {
    if CATCH_BIND_ERROR(err) {
         // Do something if 'addr' is already in use
    } else {
         panic(err)
    }
}

Есть ли способ реализовать функцию CATCH_BIND_ERROR?

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

В Windows сообщение об ошибке «Only one usage of each socket address (protocol/network address/port) is normally permitted.»

Кроме того, в случае локализации сообщение изменится.

Вот возможное решение для ошибки «Адрес уже используется»:

func isErrorAddressAlreadyInUse(err error) bool {
    errOpError, ok := err.(*net.OpError)
    if !ok {
        return false
    }
    errSyscallError, ok := errOpError.Err.(*os.SyscallError)
    if !ok {
        return false
    }
    errErrno, ok := errSyscallError.Err.(syscall.Errno)
    if !ok {
        return false
    }
    if errErrno == syscall.EADDRINUSE {
        return true
    }
    const WSAEADDRINUSE = 10048
    if runtime.GOOS == "windows" && errErrno == WSAEADDRINUSE {
        return true
    }
    return false
}

Чтобы использовать эту функцию:

conn, err := net.ListenUDP("udp", addr)
if err != nil {
    if isErrorAddressAlreadyInUse(err) {
        // Do something if 'addr' is already in use
    } else {
        panic(err)
    }
}
0 голосов
/ 03 июля 2018

Самый простой способ - просто проверить текст ошибки:

conn, err := net.ListenUDP("udp", addr)
if err != nil && err.Error() == "bind: address already in use" {
    // Failed to bind, do something
}
if err != nil {
    // Some other error
    panic(err)
}

Для такого простого случая, как этот, этого может быть достаточно. Однако этот подход несколько хрупок:

  1. Если библиотека когда-либо изменит сообщение об ошибке (это время от времени происходит, хотя, вероятно, маловероятно в этом конкретном случае), проверка прервет
  2. Если вы выполните эту проверку в какой-либо функции переноса, которая также может возвращать другие типы ошибок, вы можете, по крайней мере, теоретически, получить ложное срабатывание, если некоторые другие функции возвращают ошибку с тем же текстом (также, вероятно, маловероятно в данном случае)

Чтобы смягчить эти проблемы, вы можете проверить конкретный тип ошибки, а не просто текстовое представление. В вашем примере пакет net содержит несколько пользовательских ошибок. Метод ListenUDP возвращает net.OpError, что означает, что вы можете изучить его более внимательно. Например:

conn, err := net.ListenUDP("udp", addr)
if opErr, ok := err.(*net.OpError); ok {
    if opErr.Op == "listen" && strings.Contains(opErr.Error.Error(), "address already in use") {
        // Failed to bind, do something
    }
}
if err != nil {
    // Some other error, panic
    panic(err)
}

В этом случае мы по-прежнему зависим от текстовой проверки, поэтому все еще существует риск будущих изменений библиотеки, нарушающих тест. Но проверяя тип net.OpError, мы уменьшаем второй риск того, что может возникнуть какая-то другая ошибка с тем же текстом.

...