在 golang 中捕获 "bind: address already in use"
Catching "bind: address already in use" in golang
我想在 golang 中捕获 "bind: address already in use" 错误。
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功能吗?
简单的方法就是检查错误的文本:
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)
}
对于像这样的简单案例,这可能就足够了。然而,这种方法有些脆弱:
- 如果库更改了错误消息(这 确实 不时发生,尽管在这种特定情况下可能不太可能),检查将中断
- 如果您在某些包装函数中执行此检查,那也可能 return 其他类型的错误,至少在理论上,您可能会收到误报,如果某些其他功能 return相同文本的错误(在这种情况下也不太可能)
为了减轻这些顾虑,您可以检查特定的错误类型,而不仅仅是文本表示。在您的示例中,net package provides a few custom errors. The ListenUDP
method returns a 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
类型,我们确实减轻了第二个风险,即可能会引发具有相同文本的其他一些错误。
在 Windows 上,错误消息是“Only one usage of each socket address (protocol/network address/port) is normally permitted.
”
此外,在本地化的情况下,消息会发生变化。
以下是捕获 "Address already in use" 错误的可能解决方案:
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)
}
}
用 Go 1.13 更新 Star Brilliant 最优秀的答案error enhancements:
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
}
我想在 golang 中捕获 "bind: address already in use" 错误。
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功能吗?
简单的方法就是检查错误的文本:
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)
}
对于像这样的简单案例,这可能就足够了。然而,这种方法有些脆弱:
- 如果库更改了错误消息(这 确实 不时发生,尽管在这种特定情况下可能不太可能),检查将中断
- 如果您在某些包装函数中执行此检查,那也可能 return 其他类型的错误,至少在理论上,您可能会收到误报,如果某些其他功能 return相同文本的错误(在这种情况下也不太可能)
为了减轻这些顾虑,您可以检查特定的错误类型,而不仅仅是文本表示。在您的示例中,net package provides a few custom errors. The ListenUDP
method returns a 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
类型,我们确实减轻了第二个风险,即可能会引发具有相同文本的其他一些错误。
在 Windows 上,错误消息是“Only one usage of each socket address (protocol/network address/port) is normally permitted.
”
此外,在本地化的情况下,消息会发生变化。
以下是捕获 "Address already in use" 错误的可能解决方案:
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)
}
}
用 Go 1.13 更新 Star Brilliant 最优秀的答案error enhancements:
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
}