偶尔的“切片范围超出范围”恐慌

我正在运行一个将网络钩子转发到网络平台的脚本。将 Webhook 发送到 WebSocket 的部件会检查非活动连接,并在转发 Webhook 时尝试删除它们,有时会失败并显示以下错误:


http: panic serving 10.244.38.169:40958: runtime error: slice bounds out of range

(IP/端口总是不同的,这只是一个示例。


相关代码:


// Map holding all Websocket clients and the endpoints they are subscribed to

var clients = make(map[string][]*websocket.Conn)

var upgrader = websocket.Upgrader{}


// function to execute when a new client connects to the websocket

func handleClient(w http.ResponseWriter, r *http.Request, endpoint string) {

    conn, err := upgrader.Upgrade(w, r, nil)

    // ...

    // Add client to endpoint slice

    clients[endpoint] = append(clients[endpoint], conn)

}


// function to send a webhook to a websocket endpoint

func handleHook(w http.ResponseWriter, r *http.Request, endpoint string) {

    msg := Message{}

    // ...   

    // Get all clients listening to the current endpoint

    conns := clients[endpoint]


    if conns != nil {

        for i, conn := range conns {

            if conn.WriteJSON(msg) != nil {

                // Remove client and close connection if sending failed

                conns = append(conns[:i], conns[i+1:]...)   // this is the line that sometimes triggers the panic

                conn.Close()

            }

        }

    }


    clients[endpoint] = conns

}

我不明白为什么迭代连接并附加它们有时会引发恐慌。


慕侠2389804
浏览 130回答 1
1回答

蓝山帝景

我想说的几点:确保您的程序没有争用条件(例如。 是全局可访问的,如果同时进行读/写或写/写,则应受到保护)。clients在切片上划线时,您不需要检查非nil切片是否已经处理了该范围(请参阅我共享的代码)。for [...] range [...]它有时会发生在您的身上,因为有时失败并返回错误,并且在范围越广时删除元素的错误逻辑使您的程序恐慌。(请参阅我共享的代码)conn.WriteJSONpackage mainimport "fmt"func main() {    var conns []string = nil    // "if conns != nil" check is not required as "for [...] range [...]"    // can handle that. It is safe to use for "range" directly.    for i, conn := range conns {        fmt.Println(i, conn)    }    conns = []string{"1", "2", "3"}        // Will panic    for i := range conns {        fmt.Printf("access: %d, length: %d\n", i, len(conns))        conns = append(conns[:i], conns[i+1:]...)    }}在此示例中,您可以看到您尝试访问的索引大于或等于触发 panic 的切片的长度。我认为这个答案应该可以帮助您纠正逻辑,或者您也可以使用地图来存储连接,但它再次带有自己的警告,例如没有排序保证,即它从地图中读取的顺序。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go