Gorilla/Mux & Websocket 竞争条件。这样安全吗?
Gorilla/Mux & Websocket Race Condition. Is this safe?
我正在开发 websocket,最近开始使用 race
对竞争条件进行一些测试。
go run -race serve.go
得到这个结果:
WARNING: DATA RACE
Write at 0x0000019ab4a8 by goroutine 95:
go-api/client.ServeWs()
Previous write at 0x0000019ab4a8 by goroutine 117:
go-api/client.ServeWs()
我正在使用 gorilla/mux
并将其中一个请求升级到 websockets。我不确定它是否是由其他原因引起的,但即使是这个非常简单的设置仍然显示出竞争条件。我的 猜测 是因为 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
}
}
因为升级器不依赖于请求,你可以在package-level
创建升级器
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()
我正在开发 websocket,最近开始使用 race
对竞争条件进行一些测试。
go run -race serve.go
得到这个结果:
WARNING: DATA RACE
Write at 0x0000019ab4a8 by goroutine 95:
go-api/client.ServeWs()
Previous write at 0x0000019ab4a8 by goroutine 117:
go-api/client.ServeWs()
我正在使用 gorilla/mux
并将其中一个请求升级到 websockets。我不确定它是否是由其他原因引起的,但即使是这个非常简单的设置仍然显示出竞争条件。我的 猜测 是因为 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
}
}
因为升级器不依赖于请求,你可以在package-level
创建升级器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()