当浏览器意外关闭时,如何在Golang中通过WebSocket接收通知?

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

golang websocket how to be notified when browser closed unexpectly

问题

我正在使用golang编写一个WebSocket服务。该程序使用gollira WebSocket库来接受WebSocket请求,并在每个请求处理程序中监听RabbitMQ队列以获取消息。

问题是,当我关闭浏览器窗口时,处理程序线程仍然在运行,我猜测有一种机制可以在连接断开时通知。

我尝试监听通道request.Context().Done(),但它没有起作用。

以下是代码的翻译:

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. "github.com/gorilla/websocket"
  7. "github.com/streadway/amqp"
  8. )
  9. var (
  10. addr = "localhost:9999"
  11. upgrader = websocket.Upgrader{
  12. CheckOrigin: func(r *http.Request) bool { return true },
  13. }
  14. )
  15. var conn *amqp.Connection
  16. func watch(w http.ResponseWriter, r *http.Request) {
  17. ns := r.URL.Query().Get("ns")
  18. if ns == "" {
  19. return
  20. }
  21. c, err := upgrader.Upgrade(w, r, nil)
  22. if err != nil {
  23. log.Print("upgrade:", err)
  24. return
  25. }
  26. defer c.Close()
  27. ch, err := conn.Channel()
  28. failOnError(err, "打开通道失败")
  29. defer ch.Close()
  30. err = ch.ExchangeDeclare(
  31. "notify", // 名称
  32. "fanout", // 类型
  33. true, // durable
  34. false, // auto-deleted
  35. false, // internal
  36. false, // no-wait
  37. nil, // 参数
  38. )
  39. failOnError(err, "声明交换机失败")
  40. q, err := ch.QueueDeclare(
  41. "", // 名称
  42. false, // durable
  43. false, // delete when unused
  44. true, // exclusive
  45. false, // no-wait
  46. nil, // 参数
  47. )
  48. failOnError(err, "声明队列失败")
  49. err = ch.QueueBind(
  50. q.Name, // 队列名称
  51. ns, // 路由键
  52. "dsm_tasks_notify", // 交换机
  53. false,
  54. nil)
  55. failOnError(err, "绑定队列失败")
  56. msgs, err := ch.Consume(
  57. q.Name, // 队列
  58. "", // 消费者
  59. true, // 自动确认
  60. false, // 独占
  61. false, // 不接收本地发布的消息
  62. false, // no-wait
  63. nil, // 参数
  64. )
  65. failOnError(err, "注册消费者失败")
  66. for {
  67. select {
  68. case d := <-msgs:
  69. err = c.WriteMessage(websocket.TextMessage, d.Body)
  70. if err != nil {
  71. log.Println("写入消息失败:", err)
  72. break
  73. }
  74. case <-r.Context().Done():
  75. log.Println("连接断开")
  76. return
  77. }
  78. }
  79. }
  80. func failOnError(err error, msg string) {
  81. if err != nil {
  82. log.Fatalf("%s: %s", msg, err)
  83. panic(fmt.Sprintf("%s: %s", msg, err))
  84. }
  85. }
  86. func main() {
  87. var err error
  88. conn, err = amqp.Dial("amqp://guest:guest@localhost:5672/")
  89. failOnError(err, "连接RabbitMQ失败")
  90. defer conn.Close()
  91. http.HandleFunc("/watch", watch)
  92. log.Fatal(http.ListenAndServe(addr, nil))
  93. }

希望对你有帮助!

英文:

I am writing a websocket service in golang.
The program use gollira websocket to accept ws request, and in each request handler, it listen to rabbitmq queue for messages.

The problem is, when i close browser window, the handler thread is still running, i guess there is an mechanism to be notified when connection disconnected.

I try to listen to channel request.Context().Done(), when i doesn't work.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;log&quot;
  5. &quot;net/http&quot;
  6. &quot;github.com/gorilla/websocket&quot;
  7. &quot;github.com/streadway/amqp&quot;
  8. )
  9. var (
  10. addr = &quot;localhost:9999&quot;
  11. upgrader = websocket.Upgrader{
  12. CheckOrigin: func(r *http.Request) bool { return true },
  13. }
  14. )
  15. var conn *amqp.Connection
  16. func watch(w http.ResponseWriter, r *http.Request) {
  17. ns := r.URL.Query().Get(&quot;ns&quot;)
  18. if ns == &quot;&quot; {
  19. return
  20. }
  21. c, err := upgrader.Upgrade(w, r, nil)
  22. if err != nil {
  23. log.Print(&quot;upgrade:&quot;, err)
  24. return
  25. }
  26. defer c.Close()
  27. ch, err := conn.Channel()
  28. failOnError(err, &quot;Failed to open a channel&quot;)
  29. defer ch.Close()
  30. err = ch.ExchangeDeclare(
  31. &quot;notify&quot;, // name
  32. &quot;fanout&quot;, // type
  33. true, // durable
  34. false, // auto-deleted
  35. false, // internal
  36. false, // no-wait
  37. nil, // arguments
  38. )
  39. failOnError(err, &quot;Failed to declare an exchange&quot;)
  40. q, err := ch.QueueDeclare(
  41. &quot;&quot;, // name
  42. false, // durable
  43. false, // delete when usused
  44. true, // exclusive
  45. false, // no-wait
  46. nil, // arguments
  47. )
  48. failOnError(err, &quot;Failed to declare a queue&quot;)
  49. err = ch.QueueBind(
  50. q.Name, // queue name
  51. ns, // routing key
  52. &quot;dsm_tasks_notify&quot;, // exchange
  53. false,
  54. nil)
  55. failOnError(err, &quot;Failed to bind a queue&quot;)
  56. msgs, err := ch.Consume(
  57. q.Name, // queue
  58. &quot;&quot;, // consumer
  59. true, // auto-ack
  60. false, // exclusive
  61. false, // no-local
  62. false, // no-wait
  63. nil, // args
  64. )
  65. failOnError(err, &quot;Failed to register a consumer&quot;)
  66. for {
  67. select {
  68. case d := &lt;-msgs:
  69. err = c.WriteMessage(websocket.TextMessage, d.Body)
  70. if err != nil {
  71. log.Println(&quot;write:&quot;, err)
  72. break
  73. }
  74. case &lt;-r.Context().Done():
  75. log.Println(&quot;Disconnect&quot;)
  76. return
  77. }
  78. }
  79. }
  80. func failOnError(err error, msg string) {
  81. if err != nil {
  82. log.Fatalf(&quot;%s: %s&quot;, msg, err)
  83. panic(fmt.Sprintf(&quot;%s: %s&quot;, msg, err))
  84. }
  85. }
  86. func main() {
  87. var err error
  88. conn, err = amqp.Dial(&quot;amqp://guest:guest@localhost:5672/&quot;)
  89. failOnError(err, &quot;Failed to connect to RabbitMQ&quot;)
  90. defer conn.Close()
  91. http.HandleFunc(&quot;/watch&quot;, watch)
  92. log.Fatal(http.ListenAndServe(addr, nil))
  93. }

答案1

得分: 4

如果浏览器干净地关闭了连接,那么在读取webssocket连接时会返回一个错误。像处理任何读取错误一样清理websocket连接。

应用程序必须PING连接并期望相应的PONG来检测其他情况。聊天示例展示了如何发送PING并接收PONG。

英文:

If the browser cleanly closes the connection, then read on the webssocket connection returns an error. Cleanup the websocket connection as you would on any read error.

The application must PING the connection and expect the corresponding PONGs to detect other situations. The chat example shows how to send PINGs and receive PONGs.

huangapple
  • 本文由 发表于 2017年6月8日 12:24:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/44426606.html
匿名

发表评论

匿名网友

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

确定