Eventsource golang:如何检测客户端断开连接?

问题描述 投票:0回答:4

我正在开发基于 Twitter 主题标签的聊天室,并使用服务器发送的事件,使用包 https://github.com/antage/eventsource

我遇到了客户端断开连接的问题。我运行一个 goroutine 向客户端发送消息,但是当客户端断开连接时,goroutine 仍然运行。

不知道如何在服务器端检测客户端是否断开。

func (sh StreamHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {

    es := eventsource.New(
        &eventsource.Settings{
            Timeout:        2 * time.Second,
            CloseOnTimeout: true,
            IdleTimeout:    2 * time.Second,
            Gzip:           true,
        },
        func(req *http.Request) [][]byte {
            return [][]byte{
                []byte("X-Accel-Buffering: no"),
                []byte("Access-Control-Allow-Origin: *"),
            }
        },
    )

    es.ServeHTTP(resp, req)

    go func() {
        var id int
        for {
            id++
            time.Sleep(1 * time.Second)
            es.SendEventMessage("blabla", "message", strconv.Itoa(id))
        }
    }()

}
go server-sent-events
4个回答
14
投票

截至 2018 年 12 月,CloseNotifier 显然已被弃用。推荐的解决方案是使用

Request
上下文。以下对我有用:

done := make(chan bool)
go func() {
        <-req.Context().Done()
        done <- true
}()
<-done

6
投票

您可以使用 CloseNotifier 让您知道底层 http 连接是否已关闭。喜欢:

notify := w.(http.CloseNotifier).CloseNotify()
go func() {
    <-notify
    // connection close, do cleanup, etc.
}()

HTH


3
投票

你可以检查

ConsumersCount()

    go func() {
        var id int
        for es.ConsumersCount() > 0 {
            id++
            es.SendEventMessage("blabla", "message", strconv.Itoa(id))
            time.Sleep(1 * time.Second)
        }
        fmt.Println("closed")
    }()

有点hacky,但似乎有效。

您可能最好使用不同的包或推出自己的包,这样您就可以更好地控制 goroutine 的生命周期。您可以检测到

.Write
上的关闭连接(此包未公开)。

如果您需要,这里有一个 TCP 聊天服务器示例:chat-server。 还有一个与之配套的视频教程:tutorial

相同的基本模式也适用于 SSE。


0
投票

这种方法可行(用 Go 1.22 测试)

func (sh StreamHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {

    go func(done <-chan struct{}) {
        <-done
        fmt.Println("message", "client connection has gone away, request got cancelled")
    }(req.Context().Done())

    // .. the rest of your code here

}
© www.soinside.com 2019 - 2024. All rights reserved.