Golang TCP处理核心是net包Conn接口与生命周期管理:客户端用net.Dial建连,服务端用net.Listen+Accept监听,需goroutine并发处理、defer关闭conn、合理错误处理及超时控制。

Golang 处理 TCP 连接并不复杂,核心在于理解 net 包的 Conn 接口和生命周期管理。客户端用 net.Dial 建连,服务器用 net.Listen + Accept 等待连接;读写都基于阻塞 I/O,但可通过 goroutine 实现并发处理。
创建 TCP 服务器
使用 net.Listen("tcp", ":8080") 启动监听,返回 listener。之后在循环中调用 Accept() 阻塞等待新连接。每个连接建议起一个 goroutine 单独处理,避免串行阻塞:
- 务必检查
listener.Accept()的错误,比如监听被关闭或系统资源不足 - 连接处理函数内要 defer 关闭 conn,防止 fd 泄露
- 用
io.Copy(conn, conn)可快速实现回显服务(适合测试) - 若需解析协议(如自定义报文头),建议封装 readLoop + writeLoop,或用 bufio.Reader 提升效率
编写 TCP 客户端
调用 net.Dial("tcp", "localhost:8080") 建立连接,成功后得到 *net.TCPConn。它实现了 net.Conn 接口,可直接 Read/Write:
- 连接失败会立即返回 error,常见原因包括地址不可达、端口未监听、防火墙拦截
- Write 后建议调用
conn.CloseWrite()(半关闭)告知服务端不再发数据,尤其用于 HTTP/1.1 或自定义流协议 - 读取时注意 EOF 判断:Read 返回 (0, io.EOF) 表示对端关闭连接
- 超时控制推荐用
conn.SetDeadline()或更安全的SetReadDeadline()/SetWriteDeadline()
连接状态与错误处理
TCP 连接可能因网络中断、对端崩溃、超时等意外关闭。Golang 不自动重连,需手动处理:
立即学习“go语言免费学习笔记(深入)”;
- Read/Write 返回 error 时,先判断是否是
net.ErrClosed或io.EOF,再决定是否重连 - 使用
conn.RemoteAddr()和conn.LocalAddr()辅助日志追踪 - 临时错误(如 syscall.EAGAIN)极少在高层 API 出现,一般由 net 包内部处理;关注的是连接级错误
- 生产环境建议配合 context.WithTimeout 控制整个 dial+request 流程耗时
进阶提示:复用连接与连接池
短连接频繁建立销毁开销大。长连接场景下,可自行维护连接池(如用 sync.Pool 存 *net.TCPConn),但要注意:
- 连接空闲时需心跳保活(如发送 PING/PONG),避免被中间设备断连
- 每次使用前用
conn.Write([]byte{})尝试写入 0 字节 + SetWriteDeadline 判断是否可用 - 标准库 http.Transport 已内置 HTTP 连接池逻辑,非 HTTP 场景建议参考其设计思路
- 不要跨 goroutine 并发读写同一 conn,应配锁或拆分为读写 goroutine
基本上就这些。Golang 的 TCP 操作简洁直接,关键在理解连接生命周期、及时关闭、合理分发 goroutine 和预判常见错误。










