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
相关产品推荐
相关产品推荐

