全局变量给出 SIGSEGV

Global Variable Gives SIGSEGV

我正在使用 Fiber 开发后端。 我有一个映射,它是一个保存套接字连接的全局变量。 当我使用同一个包中的全局变量时,没问题,一切正常。但是,当我尝试使用路由函数中的套接字时,出现以下错误。

我尝试使用 mutex.lock 但没有成功。

我检查了代码,套接字在我的 sendToAll 方法中不是 nil 但它在辅助方法中变成了 nil(在 lib 中:github.com/fasthttp/websocket.(*Conn).WriteMessage )

欢迎任何建议。

谢谢。


type ConnectedSocketsContainerType struct {
    M sync.Mutex
    ConnectedSockets map[string]*websocket.Conn
}

var ConnectedSocketsContainer = ConnectedSocketsContainerType{ M:sync.Mutex{} , ConnectedSockets: make(map[string]*websocket.Conn) }

在 GET 请求处理程序的另一个包中调用该方法:

func send(socketID string,message string)  {
    sockethub.ConnectedSocketsContainer.M.Lock()
    sendToAll(message)
    sockethub.ConnectedSocketsContainer.M.Unlock()
}
func sendToAll(message string)  {
    for k := range sockethub.SocketsIDs {
        k.WriteMessage(1, []byte(message))
    }
}

错误:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x14d27f8]

goroutine 6 [running]:
github.com/fasthttp/websocket.(*Conn).WriteMessage(0xc00006aa78, 0xc00045e115, {0xc0004540f0, 0x29, 0xc00006ab2f})
        /Users/emre/go/pkg/mod/github.com/fasthttp/websocket@v1.4.3-rc.10/conn.go:753 +0x38
goserver/controllers/api.sendToAll({0xc00045e115, 0x29})
        /Users/emre/Documents/Free/SocketServer/goServer/controllers/api/socket.go:11 +0xac
goserver/controllers/api.send({0xc000456000, 0x15edfe1}, {0xc00045e115, 0x0})
        /Users/emre/Documents/Free/SocketServer/goServer/controllers/api/socket.go:22 +0x65
goserver/controllers/api.SendMessageController(0xc000128a50)
        /Users/emre/Documents/Free/SocketServer/goServer/controllers/api/socket.go:29 +0x71
github.com/gofiber/fiber/v2.(*App).next(0xc00019cb60, 0xc000456000)
        /Users/emre/go/pkg/mod/github.com/gofiber/fiber/v2@v2.23.0/router.go:127 +0x1d8
github.com/gofiber/fiber/v2.(*App).handler(0xc00019cb60, 0x10bb517)
        /Users/emre/go/pkg/mod/github.com/gofiber/fiber/v2@v2.23.0/router.go:155 +0xe5
github.com/valyala/fasthttp.(*Server).serveConn(0xc000126000, {0x16c4fa0, 0xc0000106e8})
        /Users/emre/go/pkg/mod/github.com/valyala/fasthttp@v1.31.0/server.go:2278 +0x122d
github.com/valyala/fasthttp.(*workerPool).workerFunc(0xc00014c000, 0xc00022dba0)
        /Users/emre/go/pkg/mod/github.com/valyala/fasthttp@v1.31.0/workerpool.go:223 +0xa9
github.com/valyala/fasthttp.(*workerPool).getCh.func1()
        /Users/emre/go/pkg/mod/github.com/valyala/fasthttp@v1.31.0/workerpool.go:195 +0x38
created by github.com/valyala/fasthttp.(*workerPool).getCh
        /Users/emre/go/pkg/mod/github.com/valyala/fasthttp@v1.31.0/workerpool.go:194 +0x1b5
exit status 2

go 服务器的完整示例。请查看指定有效和无效代码块的两条注释。

package main

import (
    "fmt"
    "sync"

    "github.com/gofiber/fiber/v2"
    "github.com/gofiber/websocket/v2"
)

func main() {

    app := fiber.New()

    ListenSocket(app)
    app.Get("/socket/send", SendMessageController )
    app.Listen(":3000")

}
const websocketHeaderKey = "Sec-Websocket-Key"

var ConnectedIDSockets sync.Map 

func SendMessageController( c *fiber.Ctx ) error {
    ConnectedIDSockets.Range(func(key, value interface{}) bool {
        c := value.(*websocket.Conn)
        
        if c == nil {
            // that line is not printed, c is not nil.
            fmt.Println("c is nil.")
            return true
        }

        // we have crash at that line, even we read the err.
        err := c.WriteMessage(websocket.TextMessage, []byte("message"))

        // program does not runs to here since it crashed.
        println("err:", err)
        return true
    })
    return nil
}

func ListenSocket(app *fiber.App) {
    app.Use("/ws", func(c *fiber.Ctx) error {
        if websocket.IsWebSocketUpgrade(c) {
            c.Locals("allowed", true)
            c.Locals(websocketHeaderKey, string(c.Request().Header.Peek(websocketHeaderKey)))
            return c.Next()
        }
        return fiber.ErrUpgradeRequired
    })

    app.Get("/ws/:projectKEY", websocket.New(func(c *websocket.Conn) {

        socketID := c.Locals(websocketHeaderKey).(string)

        ConnectedIDSockets.Store(socketID, c)

        // that works.
        conn, _ := ConnectedIDSockets.Load(socketID)
        socketmap := conn.(*websocket.Conn)
        socketmap.WriteMessage(1, []byte(socketID))

    }))
}

这种恐慌令人困惑,因为实际上有两个名为 websocket 的包。一个在 github.com/gofiber/websocket/v2 中,另一个在 github.com/fasthttp/websocket 中,两者都有自己的 *websocket.Conn。然而,github.com/gofiber/websocket 中的 websocket.Conn 实际上嵌入了 github.com/fasthttp/websocket 中的 websocket.Conn(我知道,糟糕的设计)让事情变得不清楚。

您对 c.WriteMessage 的调用实际上将转到 c.Conn.WriteMessage,而 c.Conn 是 nil。所以在你的 nil 检查中,你实际上需要做 if c == nil || c.Conn == nil { 来检查嵌入的结构。