net.Dial("tcp", "127.0.0.1:8080") 可建立 TCP 连接,需注意地址格式正确、显式设置超时(如 DialTimeout 或 Dialer)、连接后配置读写 deadline;服务器用 net.Listen("tcp", ":8080") 后须循环 Accept 并为每个 conn 启 goroutine 处理;收发数据需处理粘包,推荐 bufio.Scanner(简单场景)或长度头/encoder(生产环境);务必调用 conn.Close() 防文件描述符泄漏,Read 遇 io.EOF 应正常关闭。

如何用 net.Dial 建立 TCP 客户端连接
Go 标准库的 net.Dial 是最直接的 TCP 连接方式,它会自动完成 DNS 解析、建立 socket、发起三次握手。只要传入正确的网络类型和地址格式,就能拿到可用的 net.Conn。
常见错误是地址格式写错:"127.0.0.1:8080" 正确,"http://127.0.0.1:8080" 或 "127.0.0.1:8080/" 会报 dial tcp: lookup http://127.0.0.1: no such host。
- 网络类型固定用
"tcp"(IPv4/IPv6 自动适配),不用"tcp4"除非明确要禁用 IPv6 - 超时控制必须显式设置:直接调用
net.Dial没有默认超时,容易卡死;推荐用net.DialTimeout或更灵活的&net.Dialer{Timeout: 5 * time.Second}.DialContext - 连接成功后,
Conn默认不设读写超时,后续Read/Write可能永久阻塞,需自行调用SetDeadline或SetReadDeadline
如何用 net.Listen 启动 TCP 服务器
net.Listen("tcp", ":8080") 启动监听后,必须用 Accept 循环接收连接,否则客户端连上来就失败(连接被拒绝或超时)。常见误区是启动后没写 for { conn, err := listener.Accept() },导致服务“看似运行实则不可用”。
实际部署时注意:
立即学习“go语言免费学习笔记(深入)”;
- 端口小于 1024 需 root 权限(Linux/macOS),开发建议用 8080、9000 等高位端口
-
":8080"表示监听所有本地 IP(0.0.0.0:8080),如只允许本地访问,改用"127.0.0.1:8080" - 每个
Accept返回的conn是独立连接,务必启动 goroutine 处理,否则串行响应会严重拖慢吞吐
客户端与服务器之间如何收发数据
TCP 是字节流协议,没有消息边界。conn.Write([]byte("hello")) 和 conn.Read(buf) 不是一一对应的——一次 Read 可能只读到部分数据,也可能合并多次 Write 的内容。直接裸用容易粘包或截断。
简单场景可用 bufio.Scanner 按行读取(适合日志、命令行协议):
scanner := bufio.NewScanner(conn)
for scanner.Scan() {
fmt.Println("received:", scanner.Text())
}
但生产环境更推荐带长度头的二进制协议,或使用 encoding/gob / json.Encoder 封装,避免手动处理粘包逻辑。
连接关闭时要注意哪些资源泄漏点
conn.Close() 必须调用,否则文件描述符持续增长,Linux 下达到上限后新连接会失败(错误类似 dial tcp: too many open files)。goroutine 中处理完连接后,务必确保 Close 执行。
- 用
defer conn.Close()最安全,但注意它在函数返回时才触发,若 handler 函数长期运行,连接会一直占着 - 服务器侧不要在
Accept前就defer listener.Close(),否则监听立即终止 - 客户端主动断开后,服务器
Read会返回io.EOF,这是正常结束信号,不是错误,应据此退出读循环并关闭conn
真实系统里,连接生命周期管理比看起来复杂得多——超时、重连、心跳、连接池,这些都不是 Dial 和 Listen 本身能解决的。先跑通基础连接,再根据协议需求补上边界控制。










