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

Go语言中如何实现服务端WebSocket非阻塞监听?

解决golang.org/x/net/websocket非阻塞接收JSON帧的问题

虽然golang.org/x/net/websocket这个旧包没有原生的非阻塞接收方法,但可以通过两种方式实现非阻塞等待传入帧:

方法一:利用读超时模拟非阻塞

通过给连接设置读超时,让websocket.JSON.Receive()在指定时间内没有收到数据就返回超时错误,从而避免永久阻塞。示例代码:

import (
    "net"
    "time"
    "golang.org/x/net/websocket"
)

func wsHandler(ws *websocket.Conn) {
    var evnt event

    // 每次接收前设置1秒读超时
    if err := ws.SetReadDeadline(time.Now().Add(1 * time.Second)); err != nil {
        // 处理设置超时的错误
        return
    }

    err := websocket.JSON.Receive(ws, &evnt)
    if err != nil {
        // 判断是否是超时错误
        if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
            // 超时说明当前无数据,可执行其他逻辑
            return
        }
        // 处理其他错误(如连接关闭、解析失败等)
        return
    }

    // 正常处理收到的event
    // ...
}

你可以把这段逻辑放到循环里,定期检查是否有新数据,同时不阻塞主线程。

方法二:用goroutine+通道实现异步接收

把阻塞的Receive操作放到后台goroutine中,主协程通过通道接收结果,配合select实现非阻塞等待:

func wsHandler(ws *websocket.Conn) {
    msgChan := make(chan event, 1)
    errChan := make(chan error, 1)

    // 后台goroutine执行阻塞接收
    go func() {
        var evnt event
        err := websocket.JSON.Receive(ws, &evnt)
        if err != nil {
            errChan <- err
            return
        }
        msgChan <- evnt
    }()

    // 主协程通过select等待结果,同时可添加超时或其他事件监听
    select {
    case evnt := <-msgChan:
        // 处理收到的消息
        // ...
    case err := <-errChan:
        // 处理接收错误
        // ...
    case <-time.After(1 * time.Second):
        // 超时未收到消息,继续执行其他逻辑
    }
}

这种方式可以让主协程同时处理多个任务,不会被单个WebSocket的接收操作阻塞。


内容的提问来源于stack exchange,提问作者Torsten Bronger

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 02:51:14