【问题标题】:Global Variable Gives SIGSEGV全局变量给出 SIGSEGV
【发布时间】:2022-01-21 02:06:10
【问题描述】:

我正在使用 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 服务器的完整示例。请参阅指定工作和不工作代码块的两个 cmets。

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

    }))
}

【问题讨论】:

  • WriteMessage 来自哪个库?找到该文档并确保您正确调用它。就此而言,您为什么还要使用 fasthttp?他们的自述文件开头是,“对于大多数情况,net/http 更好,因为它更易于使用并且可以处理更多情况”。
  • 我正在使用光纤,我在标签中提到过。我也更新了问题,请查看新信息。在同一个包中使用变量时没有问题,从另一个路由处理程序使用时会出现问题。
  • go 中的地图可能会导致数据竞争,请参阅dave.cheney.net/2015/12/07/are-go-maps-sensitive-to-data-races
  • 你可以试试sync.Map
  • 竞争检测器是否检测到您程序中的任何问题? go run -race .

标签: go segmentation-fault mutex fibers


【解决方案1】:

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

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

【讨论】:

  • 我明白了,没错,c.Conn 为零。知道为什么 c.Conn 为零以及如何避免吗?
  • 你是对的。我从纤维框架转移到杜松子酒框架,一切正常。
  • @EmreSURK 很抱歉回答迟了,但这是因为您没有优雅地处理关闭的连接。 (诚​​然,Fiber 也没有优雅地处理它们,它不应该将其设置为 nil,而是调用 WriteMessage 应该失败)。但是是的,总的来说,我从不推荐 Fiber,它是一个糟糕的库,不符合 Go 习惯,不兼容 net/http,只会让你头疼。
猜你喜欢
  • 1970-01-01
  • 2011-09-10
  • 1970-01-01
  • 1970-01-01
  • 2017-11-09
  • 2014-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多