英文:
Global Variable Gives SIGSEGV
问题
我正在使用Fiber开发后端。我有一个作为全局变量的映射,用于保存套接字连接。当我从同一个包中使用全局变量时,一切正常,一切工作正常。但是,当我尝试从路由函数中使用套接字时,我遇到了下面的错误。
我尝试使用mutex.lock,但没有成功。
我检查了代码,在我的sendToAll方法中套接字不是nil,但在helper方法中(在lib中:github.com/fasthttp/websocket.(*Conn).WriteMessage)变为nil。
欢迎任何建议。
谢谢。
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 {
// 这一行没有打印,c 不是 nil。
fmt.Println("c is nil.")
return true
}
// 我们在这一行崩溃,即使我们读取了错误。
err := c.WriteMessage(websocket.TextMessage, []byte("message"))
// 程序没有运行到这里,因为它崩溃了。
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)
// 这个是可以工作的。
conn, _ := ConnectedIDSockets.Load(socketID)
socketmap := conn.(*websocket.Conn)
socketmap.WriteMessage(1, []byte(socketID))
}))
}
英文:
I am using Fiber to develop a backend.
I have a map that is a global variable that holds the socket connections.
When I use the global variable from the same package, no problem here, everything works fine. But, when I try to use the sockets from a route function, I am getting the error below.
I tried to use mutex.lock but no luck.
I checked the code, the socket is not nil in my sendToAll method but it becomes nil in the helper method( inside the lib: github.com/fasthttp/websocket.(*Conn).WriteMessage )
Any advice is welcome.
Thanks.
type ConnectedSocketsContainerType struct {
M sync.Mutex
ConnectedSockets map[string]*websocket.Conn
}
var ConnectedSocketsContainer = ConnectedSocketsContainerType{ M:sync.Mutex{} , ConnectedSockets: make(map[string]*websocket.Conn) }
In another package in GET request handler calls that method:
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))
}
}
The error:
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
Full example for go server. Please see two comments that specify working and not working code blocks.
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))
}))
}
答案1
得分: 2
这个错误很令人困惑,因为实际上有两个名为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
是空的。所以在你的空值检查中,你实际上需要这样做:if c == nil || c.Conn == nil {
来检查嵌入的结构体。
英文:
This panic is confusing because there are actually two packages called websocket
. One in github.com/gofiber/websocket/v2
and another one in github.com/fasthttp/websocket
, and both have their own *websocket.Conn
. However the websocket.Conn
in github.com/gofiber/websocket
actually embeds the websocket.Conn
from github.com/fasthttp/websocket
(I know, terrible design) making what's going on unclear.
Your call to c.WriteMessage
is actually going to c.Conn.WriteMessage
, and c.Conn
is what's nil. So in your nil check, you actually need to do if c == nil || c.Conn == nil {
to check the embedded struct as well.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论