Go 捕捉;绑定:地址已在使用中“;在戈兰

Go 捕捉;绑定:地址已在使用中“;在戈兰,go,error-handling,udp,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\u BIND\u ERROR函数?简单的方法就是检查错误文

我想捕获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\u BIND\u ERROR函数?

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

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)
}
对于这样一个简单的情况,这可能就足够了。然而,这种方法有些脆弱:

  • 如果库更改了错误消息(这种情况时有发生,但在这个特定实例中可能不太可能),检查将中断
  • 如果在某个包装函数中执行此检查,也可能返回其他类型的错误,那么至少在理论上,如果其他函数返回具有相同文本的错误,则可能会收到误报(在这种情况下也可能不太可能)
  • 为了缓解这些问题,您可以检查特定的错误类型,而不仅仅是文本表示。在您的示例中,包提供了一些自定义错误。该方法返回一个值,这意味着您可以更仔细地检查它。例如:

    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
    类型,我们确实降低了第二个风险,即可能会出现其他一些具有相同文本的错误。

    在Windows上,错误消息是“
    通常只允许使用每个套接字地址(协议/网络地址/端口)。

    此外,在本地化的情况下,消息将发生更改

    以下是捕获“地址已在使用”错误的可能解决方案:

    要使用此功能,请执行以下操作:

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

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

    func-isErrorAddressAlreadyInUse(err-error)bool{
    变量eOsSyscall*os.SyscallError
    if!errors.As(err,&eOsSyscall){
    返回错误
    }
    var Errno syscall.Errno//不需要“*”(ptr),因为它已经是一个ptr(uintpttr)
    if!errors.As(eOsSyscall,&errno){
    返回错误
    }
    如果errno==syscall.EADDRINUSE{
    返回真值
    }
    常数WSAEADDRINUSE=10048
    如果runtime.GOOS==“windows”&&errno==WSAEADDRINUSE{
    返回真值
    }
    返回错误
    }
    
    检查字符串是一个危险的想法。查看并验证这样的内容是否有助于您构造正确的错误类型,以对照您在Windows上的调用返回的结果进行检查,错误消息是“每个套接字地址(协议/网络地址/端口)通常只允许使用一次”。我请您检查我的支持Windows的解决方案。:-)@StarBrilliant:这是一个很好的例子,说明为什么检查错误消息的文本是一种不好的做法:)
    errors.As()
    应该可以与syscall.Errno一起工作;您只需要传入指向
    syscall.Errno
    的指针,而不是指向指针的指针,因为
    syscall.Errno
    是实现
    error
    的类型,而不是
    *syscall.Errno
    <代码>变量Errno syscall.Errno<代码>如果!errors.As(eOsSyscall.Err,&errErrno){return false}谢谢@thepaul,我已经更新了我的代码片段。
    conn, err := net.ListenUDP("udp", addr)
    if err != nil {
        if isErrorAddressAlreadyInUse(err) {
            // Do something if 'addr' is already in use
        } else {
            panic(err)
        }
    }