Golang中如何处理“use of closed network connection”错误
Golang中如何处理“use of closed network connection”错误
对于 HTTP 的 ListenAndServe 和 listener.Close 操作,会触发监听器产生 “use of closed network connection” 错误。
我链接了相关的问题,其中包含示例代码。我不确定如何以优雅的方式解决这个错误。 有人能帮忙吗?
受影响/包:net。“use of closed network connection”
你使用的 Go 版本是什么 (go version)?
go 1.18.0
源代码
package main
import (
"net"
"net/http"
"time"
)
func main() {
listener, err := net.Listen("tcp", net.JoinHostPort("0.0.0.0", "0"))
if nil!=err{
panic(err)
}
httpServer := &http.Server{}
go func() {
err :=httpServer.Serve(listener)
if nil!=err && err!=http.ErrServerClosed && err!=net.ErrClosed{
panic(err)
}
}()
time.Sleep(time.Second)
err = listener.Close()
if nil!=err{
panic(err)
}
time.Sleep(time.Second)
}
错误
panic: accept tcp [::]:64309: use of closed network connection
goroutine 6 [running]:
main.main.func1()
.../main.go:19 +0xb3
created by main.main
.../main.go:16 +0x15a
exit status 2
问题:
这种情况下的 panic 是正常的吗?为什么我关闭监听器后,服务器会收到一个不属于 http.ErrServerClosed 的错误?
处理这个错误的正确方法是什么?
更多关于Golang中如何处理“use of closed network connection”错误的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你的主控制流将首先启动服务器(在单独的 Go 协程中)。 然后它将关闭服务器正在提供服务的套接字(调用 listener.Close())。
查看 waitgroup 示例,了解如何等待其他 Go 协程完成。
更多关于Golang中如何处理“use of closed network connection”错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在 Go 中处理 “use of closed network connection” 错误,关键在于正确区分正常的服务器关闭和意外错误。你的代码中 panic 是因为错误检查逻辑不够完整。
问题分析
当调用 listener.Close() 时,正在运行的 httpServer.Serve(listener) 会立即返回一个错误。这个错误是 net.ErrClosed 类型的,但你的错误检查没有正确处理所有情况。
解决方案
方法1:使用 http.Server.Shutdown()(推荐)
这是最优雅的方式,可以优雅地关闭 HTTP 服务器:
package main
import (
"context"
"net"
"net/http"
"time"
)
func main() {
listener, err := net.Listen("tcp", net.JoinHostPort("0.0.0.0", "0"))
if err != nil {
panic(err)
}
httpServer := &http.Server{}
go func() {
err := httpServer.Serve(listener)
// 服务器正常关闭时,Serve 会返回 ErrServerClosed
if err != nil && err != http.ErrServerClosed {
panic(err)
}
}()
time.Sleep(time.Second)
// 使用 Shutdown 优雅关闭服务器
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := httpServer.Shutdown(ctx); err != nil {
panic(err)
}
time.Sleep(time.Second)
}
方法2:更完善的错误检查
如果你需要直接操作 listener,可以这样处理错误:
package main
import (
"errors"
"net"
"net/http"
"time"
)
func main() {
listener, err := net.Listen("tcp", net.JoinHostPort("0.0.0.0", "0"))
if err != nil {
panic(err)
}
httpServer := &http.Server{}
go func() {
err := httpServer.Serve(listener)
// 检查多种可能的关闭错误
if err != nil &&
err != http.ErrServerClosed &&
!errors.Is(err, net.ErrClosed) {
panic(err)
}
}()
time.Sleep(time.Second)
err = listener.Close()
if err != nil {
panic(err)
}
time.Sleep(time.Second)
}
方法3:使用自定义错误处理
对于更复杂的场景,可以创建错误处理函数:
package main
import (
"errors"
"net"
"net/http"
"time"
)
func isClosedError(err error) bool {
if err == nil {
return false
}
// 检查标准库错误
if errors.Is(err, net.ErrClosed) ||
err == http.ErrServerClosed {
return true
}
// 检查错误字符串(作为后备方案)
errStr := err.Error()
return errStr == "use of closed network connection" ||
errStr == "accept tcp: use of closed network connection"
}
func main() {
listener, err := net.Listen("tcp", net.JoinHostPort("0.0.0.0", "0"))
if err != nil {
panic(err)
}
httpServer := &http.Server{}
go func() {
err := httpServer.Serve(listener)
if err != nil && !isClosedError(err) {
panic(err)
}
}()
time.Sleep(time.Second)
err = listener.Close()
if err != nil {
panic(err)
}
time.Sleep(time.Second)
}
关键点
- 使用
http.Server.Shutdown()是处理 HTTP 服务器关闭的最佳实践 - 直接关闭 listener 时,
Serve()方法会返回net.ErrClosed错误 - Go 1.13+ 推荐使用
errors.Is()进行错误类型检查 - 错误信息可能因 Go 版本和操作系统略有不同
在你的具体案例中,panic 是因为错误检查没有捕获到 net.ErrClosed。使用 errors.Is(err, net.ErrClosed) 可以正确识别这种关闭错误。

