英文:
Gorilla/Mux & Websocket Race Condition. Is this safe?
问题
我正在处理一个websocket,并最近开始使用race
进行一些竞态条件的测试。
go run -race serve.go
得到以下结果:
警告:数据竞争
goroutine 95 在 0x0000019ab4a8 处写入:
go-api/client.ServeWs()
之前的写入在 0x0000019ab4a8 处由 goroutine 117 完成:
go-api/client.ServeWs()
我正在使用gorilla/mux
,并将其中一个请求升级为websocket。我不确定是否是由其他原因引起的,但即使是这个相当简单的设置仍然显示出竞态条件。我猜测是因为websocket
同时被两个例程写入,但只要两个请求都被升级,这是否重要?或者可能由于竞态条件而导致连接断开?
//serve.go
mux.HandleFunc("/data", func(w http.ResponseWriter, r *http.Request) {
client.ServeWs(w, r)
})
//client.go
func ServeWs(w http.ResponseWriter, r *http.Request) {
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
_, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
}
英文:
I'm working on a websocket and recently started doing some tests for race conditions using race
.
go run -race serve.go
Getting this result:
WARNING: DATA RACE
Write at 0x0000019ab4a8 by goroutine 95:
go-api/client.ServeWs()
Previous write at 0x0000019ab4a8 by goroutine 117:
go-api/client.ServeWs()
I'm using gorilla/mux
and am upgrading one of the requests to websockets. I wasn't sure if it was being caused by something else, but even this pretty simple setup is still showing a race condition. My guess was because websocket
was being written to by both routines at the same time, but as long as both requests get upgraded, does it matter? Or is it possible a connection is being dropped due to the race condition?
//serve.go
mux.HandleFunc("/data", func(w http.ResponseWriter, r *http.Request) {
client.ServeWs(w, r)
})
//client.go
func ServeWs(w http.ResponseWriter, r *http.Request) {
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
}
_, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
}
答案1
得分: 0
因为升级器不依赖于请求,所以可以在包级别创建升级器:
var upgrader = websocket.Upgrader{ ... fields as in ServeWs ... }
然后从ServeWs函数中移除对升级器的赋值操作:
func ServeWs(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer c.Close()
}
英文:
Because the upgrader is not dependent on the request, you can create the upgrader at package-level
var upgrader = websocket.Upgrader{ ... fields as in ServeWs ... }
and remove the assignment to the upgrader from ServeWs.
func ServeWs(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer c.Close()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论