You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Gorilla WebSocket连接建立约1分钟后出现Read TCP I/O超时问题

解决WebSocket连接1分钟IO超时断开问题

你遇到的read tcp ... i/o timeout错误,本质是空闲TCP连接被中间网络设备(防火墙、负载均衡等)主动断开——这类设备通常默认1分钟的空闲超时,当WebSocket连接超过1分钟没有数据传输时,就会被切断。你的当前代码只在被动等待客户端发消息,没有维持连接活跃的机制,所以触发了超时。

解决方案:添加WebSocket心跳机制

通过服务器定期发送Ping帧、客户端自动回复Pong帧的方式,让连接保持活跃,避免被中间设备判定为空闲断开。

修改后的代码示例:

import "time"

func (c *YourConnectionType) handleWebSocket() {
    // 1. 设置读超时,并注册Pong处理函数(收到Pong后重置超时)
    err := c.RawConn.SetReadDeadline(time.Now().Add(30 * time.Second))
    if err != nil {
        c.logger.Errorf("set read deadline for %s failed: %v", c.connectionID, err)
        return
    }

    c.RawConn.SetPongHandler(func(appData string) error {
        // 收到客户端的Pong回复,重置读超时
        return c.RawConn.SetReadDeadline(time.Now().Add(30 * time.Second))
    })

    // 2. 启动goroutine定期发送Ping帧(间隔要小于读超时时间)
    pingTicker := time.NewTicker(25 * time.Second)
    defer pingTicker.Stop()

    go func() {
        for {
            select {
            case <-pingTicker.C:
                // 发送Ping帧给客户端
                if err := c.RawConn.WriteMessage(websocket.PingMessage, nil); err != nil {
                    c.logger.Errorf("send ping to %s failed: %v", c.connectionID, err)
                    return
                }
            case <-c.ctx.Done():
                // 连接上下文结束,退出goroutine
                return
            }
        }
    }()

    // 3. 原有的消息读取循环
    for {
        messageType, message, err := c.RawConn.ReadMessage()
        if err != nil {
            if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
                c.logger.Errorf("websocket unexpected close from %s: %v", c.connectionID, err)
            } else {
                c.logger.Debugf("websocket connection closed from %s: %v", c.connectionID, err)
            }
            break
        }
        fmt.Printf("Received message: %s\n", message)
    }
}

关键逻辑说明:

  • 读超时设置:把读超时设为30秒,确保在连接真的异常时能及时检测到。
  • Ping/Pong机制:每25秒发送一次Ping帧(间隔小于读超时),客户端收到后会自动回复Pong(浏览器原生WebSocket默认支持),服务器收到Pong就重置读超时,让连接一直处于活跃状态。
  • 异常处理:如果客户端长时间没回复Pong,读超时会触发,服务器就能捕获到错误并断开连接,避免无效连接占用资源。

额外注意事项

  • 若使用自定义JavaScript客户端而非浏览器原生WebSocket,需要确保客户端实现了Pong响应逻辑,否则服务器的Ping无法得到回复,依然会触发超时。
  • 如果有权限调整部署环境的防火墙/负载均衡配置,可以适当延长空闲超时时间,但这只是辅助手段,心跳机制才是跨环境通用的可靠解决方案。

内容的提问来源于stack exchange,提问作者Andrew Cui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 20:45:34