如何在Golang中搭建TCP服务器_Golang net Listen与Accept方法

10次阅读

go中Listen后必须循环调用Accept并配合goroutine处理并发连接,否则仅能处理首个连接;每个conn需设读写超时并显式关闭以防fd泄漏。

如何在Golang中搭建TCP服务器_Golang net Listen与Accept方法

Listen 之后必须调用 Accept 才能接收连接

Go 的 net.Listen 只是创建监听套接字并绑定地址,它不阻塞、也不处理任何客户端连接;真正等待并获取新连接的是 Accept。常见错误是只调用 Listen 就结束程序,结果服务看似“启动了”,但根本收不到请求。

  • Listen 返回 net.Listener 接口,需持续调用其 Accept() 方法
  • Accept() 是阻塞调用,返回 net.Conn(代表一个具体连接)和可能的错误
  • 若不循环调用 Accept,服务器只能处理第一个连接就退出

Accept 必须配合 goroutine 处理并发连接

每个 Accept 返回的 net.Conn 是单次连接,读写操作(如 Read/Write)也是阻塞的。如果在线程里同步处理,后续连接会排队等待——这不是“服务器没响应”,而是逻辑卡死在上一个连接的 I/O 上。

  • 典型模式:主 goroutine 循环 Accept,每拿到一个 conn 就起一个新 goroutine 处理
  • 不加 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) }

Listen 地址字符串格式与端口占用问题

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"
  • linux/macOS 下可复用端口需设置 SO_REUSEADDR,Go 默认不启用;可通过 net.ListenConfig 配置 Control 函数实现

Accept 返回的 Conn 需要显式超时控制

net.Conn 默认无读写超时,一旦客户端异常断连或发半包,Read 可能永远阻塞。不能依赖 listener.SetDeadline(它不存在),而要对每个 conn 单独设。

立即学习go语言免费学习笔记(深入)”;

  • 使用 conn.SetReadDeadlineconn.SetDeadline 设置绝对时间点
  • 推荐用 conn.SetReadTimeout(相对时长),更直观
  • 超时后 Read 返回 io.EOF 或带 net.ErrTimeout 的错误,需检查并退出处理 goroutine

实际部署中,最易被忽略的是连接超时和资源清理——没有超时,几百个空闲连接就能拖垮服务;没有 defer conn.Close(),文件描述符耗尽后 Accept 会开始报 "too many open files"

text=ZqhQzanResources