在golang中捕获“绑定:地址已在使用中”

问题描述:

I want to catch "bind: address already in use" error in 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)
    }
}

Is there any way to implement CATCH_BIND_ERROR function?

我想在golang中捕获“绑定:地址已在使用中”错误。 p>

  conn,err:= net.ListenUDP(“ udp”,addr)
if err!= nil {
如果CATCH_BIND_ERROR(err){
 //如果'addr'已经在使用 
}其他{
 panic(err)
} 
} 
  code>  pre> 
 
 

有没有办法实现CATCH_BIND_ERROR函数? p>

The easy way is just to check the text of the 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)
}

For a simple case like this, this may be sufficient. This approach is somewhat fragile, however:

  1. If the library ever changes the error message (this does happen from time to time, although is probably unlikely in this specific instance), the check will break
  2. If you do this check in some wrapping function, that may also return other types of errors, you may, at least in theory, receive a false positive, if some other functionality returns an error with the same text (also probably unlikely in this case)

To mitigate these concerns, you may be able to check for the specific error type, rather than just a textual representation. In your example, the net package provides a few custom errors. The ListenUDP method returns a net.OpError, which means you can examine it more closely. For example:

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

In this case, we still depend on a textual check, so there's still a risk of future library changes breaking the test. But by checking for the net.OpError type, we do mitigate the second risk, that some other error, with the same text, may be raised.

On Windows, the error message is "Only one usage of each socket address (protocol/network address/port) is normally permitted."

Additionally, in case of localization, the message would change.

Here is a possible solution to catch "Address already in use" error:

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
}

To use this function:

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