请教一个 GO websocket goroutine 无限增长问题

使用Go 写了一个websocket 广播服务,通过pprof工具查看,发现每次刷新客户端链接,goroutine数量都会增长,请知道的大佬指点一下,这是啥问题,如何限制

服务端 server.go

package main

import (
    "fmt"
    "golang.org/x/net/websocket"
    "net/http"
    _ "net/http/pprof"
    "time"
)
// 建立连接池,用于广播消息
var conns = make(map[string]*websocket.Conn)
var messageChan = make(chan string, 10)

func main() {
    http.Handle("/", websocket.Handler(func(conn *websocket.Conn) {
        conns[conn.RemoteAddr().String()] = conn
        for {
            var reply string
            if err := websocket.Message.Receive(conn, &reply); err != nil {
            }
            // 防止空转
            time.Sleep(1 * time.Second)
        }
    })) // 设置访问的路由
    // 广播消息
    go BroadMessages(messageChan)
    // 开始广播
    go SendMessage(messageChan)
    http.ListenAndServe(":8080", nil) // 设置监听的端口

}

// SendMessage 1秒钟广播一次
func SendMessage(messages chan string) {
    for {
        msg := fmt.Sprintf("这里是广播时间:,%d",time.Now().Unix())
        messages <- msg
        time.Sleep(1 * time.Second)
    }
}

// BroadMessages 向所有连接上的乡亲们发广播
func BroadMessages(messages chan string) {
    for {
        // 不断从通道里读取消息
        msg := <-messages
        fmt.Println(msg)
        // 向所有的乡亲们发消息
        for key, conn := range conns {
            if err := websocket.Message.Send(conn, msg); err != nil {
                delete(conns, key)
            }
        }
    }
}

客户端是使用简单的js链接的websocket服务

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script>
    var ws = new WebSocket("ws://127.0.0.1:8080");

    ws.onopen = function(evt) {
        ws.send("Hello WebSockets!");
    };

    ws.onmessage = function(evt) {
        console.log(evt.data)
    };

    ws.onclose = function(evt) {
        console.log("Connection closed.");
    };
</script>
</html>

服务启动后,客户端访问需要痛殴ide启动一个服务代开才可以,go的websocket会检查请求头,检查来源地址才可以链接成功

请教一个 GO websocket goroutine 无限增长问题

打开客户端方式e.g.

请教一个 GO websocket goroutine 无限增长问题

链接后效果:

请教一个 GO websocket goroutine 无限增长问题

go pprof 工具显示(查看方式可以直接打开:http://127.0.0.1:8080/debug/pprof/)

请教一个 GO websocket goroutine 无限增长问题

白胖子
讨论数量: 15

点击 goroutine 的链接进去看具体增加的是什么 goroutine,看完你就知道为什么了

2年前 评论

每个连接进来都退不出去,你要判断一下读取数据时,客户端断开时读到什么数据,然后退出hand函数。https://learnku.com/articles/48418,以前写的一个可以参考下

2年前 评论
appleboy

github.com/googollee/go-socket.io/...

類似的問題,也在 go-socket io 套件上面出現。

2年前 评论
for {
    var reply string
    if err := websocket.Message.Receive(conn, &reply); err != nil {
        // 出错了跳出for循环,return或break
        // 浏览器刷新页面,会重新建立一个连接,之前的连接对象会被浏览器回收,这里再Receive肯定会报错的,具体是什么错误,打印日志看一下,应该是reset,EOF之类的错误。另外像是断网,可能不会返回错误,因为没有设置读取超时时间。如果设置了,应该是timeout类的错误。
        return
    }
    // 防止空转
    time.Sleep(1 * time.Second)
}
2年前 评论

@zxdstyle 没有呀,我手机也可以打开的正常查看的 :flushed:

2年前 评论

设计有问题吧,一个ip先看有没有再添加,而不是没请求一次就加一个吧

2年前 评论
for {
            var reply string
            if err := websocket.Message.Receive(conn, &reply); err != nil {
            }
            // 防止空转
            time.Sleep(1 * time.Second)
        }

这里是个死循环,你每连接一个用户就多一个死循环

2年前 评论
zxdstyle 2年前
renxiaotu (作者) 2年前

@zxdstyle 看到了,每次请求websocket都会启一个goroutine 去处理内容,由于我这里加了for循环,并且没有退出条件,所以这个goroutine会一直存在。在for循环里面添加一个退出机制就行了,比如 向客户端发送心跳包,失败次数达到阈值就break。
"golang.org/x/net/websocket" 这个包好像不太友好,没有检查链接是否断开的机制,需要自己处理

2年前 评论

@deatil “conn.RemoteAddr().String()” 这个是客户端的地址,其实每一次刷新或者每一次进来的请求,都会重新建立一个goroutine去处理,所以要进行覆盖或者按照新的链接插入

2年前 评论

每新建一个连接增加一个协程应该是正常的吧。这里我感觉你的问题应该是连接关闭后,协程数量没有减少。

2年前 评论

@lxswx 是的,增加一个心跳检查来关闭就可以了

2年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!