Gorilla/Mux和Websocket的竞争条件。这个安全吗?

huangapple go评论86阅读模式
英文:

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()

huangapple
  • 本文由 发表于 2022年3月12日 01:23:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/71442393.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定