全局变量导致SIGSEGV错误

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

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/websocketwebsocket.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.

huangapple
  • 本文由 发表于 2021年12月19日 00:32:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/70405169.html
匿名

发表评论

匿名网友

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

确定