listenandserve 启动即退出因未注册路由或误用 http 包实现 tcp 服务;纯 tcp 应用 net.listen + accept 循环,每连接需独立 goroutine 并设读写超时,关闭时用 waitgroup 和 context 协调,绑定地址需为 0.0.0.0 而非 127.0.0.1。

listenAndServe 为什么一启动就退出?
因为 http.ListenAndServe 是阻塞调用,但它默认监听的是 HTTP(非纯 TCP),如果你没注册任何路由,它会返回 http: Server closed 或直接 panic;更常见的是你误用了 net/http 包去干纯 TCP 的事——TCP 服务器不该从 http 包起步。
- 纯 TCP 服务必须用
net.Listen("tcp", ":8080"),不是http.ListenAndServe - 如果用了
http.ListenAndServe却没调http.HandleFunc,会报http: panic serving ...: mux: no match for request -
net.Listen返回的net.Listener必须手动Accept(),不写循环就会立即退出
Accept 循环里为什么只处理一个连接就卡住?
因为 listener.Accept() 是阻塞的,但后续对每个 conn 的读写也默认阻塞,若客户端不发数据或不关闭连接,conn.Read() 就一直挂起,整个 goroutine 停住,新连接进不来。
- 每个
conn必须起独立 goroutine 处理:go handleConn(conn) - 不设超时的话,一个死连接能拖垮整个服务器;加
conn.SetReadDeadline和conn.SetWriteDeadline - 别在主线程里直接
Read,否则Accept被阻塞,新连接排队等待
如何安全地关闭正在运行的 TCP 服务器?
Go 没有内置的“优雅关闭 TCP listener”机制,listener.Close() 会立刻断开所有未完成的 Accept,但已 Accept 的 conn 不受影响——关不关它们,得你自己控制。
- 用
sync.WaitGroup跟踪活跃连接数,关闭前先listener.Close(),再wg.Wait() - 给每个
handleConn传入context.Context,在Read前检查ctx.Err() - 不要依赖
defer conn.Close()就以为万事大吉:goroutine 可能卡在 I/O,得靠 deadline 或 context 主动中断
为什么本地测试通,部署到 Linux 服务器就连不上?
大概率是端口、防火墙或绑定地址问题。Go 默认绑定 127.0.0.1,不是 0.0.0.0;而很多云服务器默认不开放非标准端口。
立即学习“go语言免费学习笔记(深入)”;
- 检查
net.Listen("tcp", ":8080")—— 冒号前无 IP 表示绑定所有接口,等价于"0.0.0.0:8080";写成"127.0.0.1:8080"就只能本地连 - Linux 上用
ss -tlnp | grep :8080看是否真在监听0.0.0.0 - 云厂商安全组、本地
ufw或firewalld都可能拦掉端口,别只查 Go 代码
conn 在异常网络下不泄漏 goroutine、不堆积缓冲、不卡死主线程——这些细节不会报错,但会在高并发或弱网时突然暴露。











