Go中Listen后必须循环调用Accept并配合goroutine处理并发连接,否则仅能处理首个连接;每个conn需设读写超时并显式关闭以防fd泄漏。
Go 的 net.Listen 只是创建监听套接字并绑定地址,它不阻塞、也不处理任何客户端连接;真正等待并获取新连接的是 Accept。常见错误是只调用 Listen 就结束程序,结果服务看似“启动了”,但根本收不到请求。
Listen 返回 net.Listener 接口,需持续调用其 Accept() 方法Accept() 是阻塞调用,返回 net.Conn(代表一个具体连接)和可能的错误Accept,服务器只能处理第一个连接就退出每个 Accept 返回的 net.Conn 是单次连接,读写操作(如 Read/Write)也是阻塞的。如果在主线程里同步处理,后续连接会排队等待——这不是“服务器没响应”,而是逻辑卡死在上一个连接的 I/O 上。
Accept,每拿到一个 conn 就起一个新 goroutine 处理conn:应在处理 goroutine 结束前调用 conn.Close(),否则 fd 泄漏listener, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
defer listener.Close()
for {

conn, err := listener.Accept()
if err != nil {
log.Println("Accept error:", err)
continue // 不要直接 break,避免整个服务中断
}
go func(c net.Conn) {
defer c.Close()
buf := make([]byte, 1024)
n, _ := c.Read(buf)
c.Write(buf[:n])
}(conn)
}
net.Listen("tcp", addr) 的 addr 必须是形如 "host:port" 的字符串。本地监听常用 ":8080"(等价于 "localhost:8080"),但要注意:
":8080" 监听所有 IPv4/IPv6 地址,"127.0.0.1:8080" 仅限 IPv4 回环Listen 返回 *net.OpError,错误信息含 "bind: address already in use"
SO_REUSEADDR,Go 默认不启用;可通过 net.ListenConfig 配置 Control 函数实现net.Conn 默认无读写超时,一旦客户端异常断连或发半包,Read 可能永远阻塞。不能依赖 listener.SetDeadline(它不存在),而要对每个 conn 单独设。
conn.SetReadDeadline 或 conn.SetDeadline 设置绝对时间点conn.SetReadTimeout(相对时长),更直观Read 返回 io.EOF 或带 net.ErrTimeout 的错误,需检查并退出处理 goroutine实际部署中,最易被忽略的是连接超时和资源清理——没有超时,几百个空闲连接就能拖垮服务;没有 defer conn.Close(),文件描述符耗尽后 Accept 会开始报 "too many open files"。