在golang

时间:2018-07-03 10:12:11

标签: go error-handling udp

我想在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函数?

3 个答案:

答案 0 :(得分:5)

简单的方法就是检查错误文本:

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类型,我们确实减轻了第二种风险,即可能会引发其他一些错误,但文本相同。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

使用 Go 1.13 的 error enhancements 更新 Star Brilliant 的最佳答案:

func isErrorAddressAlreadyInUse(err error) bool {
    var eOsSyscall *os.SyscallError
    if !errors.As(err, &eOsSyscall) {
        return false
    }
    var errErrno syscall.Errno // doesn't need a "*" (ptr) because it's already a ptr (uintptr)
    if !errors.As(eOsSyscall, &errErrno) {
        return false
    }
    if errErrno == syscall.EADDRINUSE {
        return true
    }
    const WSAEADDRINUSE = 10048
    if runtime.GOOS == "windows" && errErrno == WSAEADDRINUSE {
        return true
    }
    return false
}
相关问题