修复Go语言TCP客户端的连接故障问题
嘿,这个场景太常见了——服务器偶尔崩溃重启,客户端总不能一直僵死在那里对吧?咱们给客户端加个自动重连+错误恢复机制就能搞定,下面是具体的实现思路和代码示例:
核心解决方案:错误捕获 + 循环重连
当收发过程中出现错误(连接失效、读写失败),我们需要:
- 立即关闭当前失效的连接,避免资源泄漏
- 等待一段合理时间(避免频繁重试给服务器添负担)
- 尝试重新建立TCP连接,直到成功
- 重新初始化读写器,恢复数据收发循环
完整代码示例
package main import ( "bufio" "log" "net" "time" ) func main() { // 外层循环负责重连逻辑 retryDelay := 3 * time.Second maxRetryDelay := 30 * time.Second for { // 尝试建立连接 conn, err := net.Dial("tcp", "127.0.0.1:3456") if err != nil { log.Printf("连接服务器失败: %v,%v后重试", err, retryDelay) time.Sleep(retryDelay) // 指数退避:重试间隔翻倍,直到上限 if retryDelay < maxRetryDelay { retryDelay *= 2 } continue } // 连接成功后重置重试间隔 retryDelay = 3 * time.Second log.Println("✅ 成功连接到服务器") // 初始化读写器 reader := bufio.NewReader(conn) writer := bufio.NewWriter(conn) // 进入数据收发循环,出错则跳出到外层重连 if err := runClientLoop(reader, writer, conn); err != nil { log.Printf("❌ 收发过程出错: %v", err) } // 关闭当前失效连接 if err := conn.Close(); err != nil { log.Printf("关闭连接时出错: %v", err) } log.Println("🔌 连接已断开,准备重连...") } } // runClientLoop 负责具体的收发逻辑,出错时返回错误 func runClientLoop(reader *bufio.Reader, writer *bufio.Writer, conn net.Conn) error { for { // 示例:发送数据(替换成你的实际数据) sendData := []byte("Hello from client!\n") if _, err := writer.Write(sendData); err != nil { return err } // 必须Flush,否则数据可能留在缓冲区没发出去 if err := writer.Flush(); err != nil { return err } log.Println("已发送数据:", string(sendData)) // 读取服务器响应 resp, err := reader.ReadString('\n') if err != nil { return err } log.Printf("收到服务器响应: %s", resp) // 模拟业务间隔,可根据实际情况调整 time.Sleep(1 * time.Second) } }
关键细节说明
- 指数退避重试:比起固定间隔,指数退避能避免服务器刚重启时就被大量重试请求冲击,同时在长时间无法连接时不会浪费过多资源。
- 资源清理:每次重连前必须关闭旧连接,否则会导致文件句柄泄漏,最终客户端会因为资源耗尽无法建立新连接。
- 错误穿透:把收发逻辑封装到单独函数,出错时直接返回,让外层循环统一处理重连,代码更清晰。
- Flush缓冲区:使用
bufio.Writer时一定要记得调用Flush(),否则数据可能一直留在客户端缓冲区,不会发送到服务器。
如果需要更精细的错误处理,还可以判断具体的错误类型(比如net.ErrClosed、syscall.ECONNRESET等),针对不同错误做不同处理,但上面的基础版本已经能覆盖大部分场景啦。
内容的提问来源于stack exchange,提问作者insumity
相关产品推荐
相关产品推荐

