Eventsource golang : how to detect client disconnection?

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

Eventsource golang : how to detect client disconnection?

问题

我正在使用https://github.com/antage/eventsource包基于Twitter标签开发聊天室,并使用服务器发送事件。我遇到了一个关于客户端断开连接的问题。我在一个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))
		}
	}()

}

请问有什么我可以帮助你的吗?

英文:

I'm developing chat rooms based on Twitter hashtag with Server sent events, with the package https://github.com/antage/eventsource

I have a problem concerning the disconnection of the client. I run a goroutine to send messages to the client, but when the client disconnects, the goroutine still runs.

I don't know how to detect on the server side that the client is disconnected.

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

}

答案1

得分: 11

截至2018年12月,显然CloseNotifier已被弃用。推荐的解决方案是使用Request上下文。以下代码对我有效:

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

As of December 2018, apparently CloseNotifier is deprecated. The recommended solution is to use the Request Context. The following worked for me:

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

答案2

得分: 6

你可以使用CloseNotifier来判断底层的HTTP连接是否关闭。例如:

notify := w.(http.CloseNotifier).CloseNotify()
go func() {
	<-notify
	// 连接关闭,进行清理等操作
}()

希望对你有帮助。

英文:

You can use CloseNotifier which lets you know if the underlying http connection has closed. Like:

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

HTH

答案3

得分: 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")
}()

这种方法可能有点巧妙,但似乎可以工作。

你可能最好使用其他包或自己编写代码,这样你可以更好地控制goroutine的生命周期。你可以在.Write方法中检测到连接关闭(该包没有公开该方法)。

如果你想要的话,这里有一个使用TCP的聊天服务器示例:chat-server
还有一个配套的视频教程:tutorial

对于SSE,相同的基本模式应该适用。

英文:

You could check ConsumersCount():

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

Kinda hacky, but it seems to work.

You may be better off using a different package or rolling your own so you could have better control over the lifetime of your goroutines. You can detect a closed connection on .Write (which this package isn't exposing).

If you want here's an example chat server in TCP: chat-server.
And a video tutorial to go with it: tutorial.

The same basic pattern should work for SSE.

huangapple
  • 本文由 发表于 2015年8月21日 00:27:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/32123546.html
匿名

发表评论

匿名网友

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

确定