英文:
golang websocket how to be notified when browser closed unexpectly
问题
我正在使用golang编写一个WebSocket服务。该程序使用gollira WebSocket库来接受WebSocket请求,并在每个请求处理程序中监听RabbitMQ队列以获取消息。
问题是,当我关闭浏览器窗口时,处理程序线程仍然在运行,我猜测有一种机制可以在连接断开时通知。
我尝试监听通道request.Context().Done(),但它没有起作用。
以下是代码的翻译:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
"github.com/streadway/amqp"
)
var (
addr = "localhost:9999"
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
)
var conn *amqp.Connection
func watch(w http.ResponseWriter, r *http.Request) {
ns := r.URL.Query().Get("ns")
if ns == "" {
return
}
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
ch, err := conn.Channel()
failOnError(err, "打开通道失败")
defer ch.Close()
err = ch.ExchangeDeclare(
"notify", // 名称
"fanout", // 类型
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // 参数
)
failOnError(err, "声明交换机失败")
q, err := ch.QueueDeclare(
"", // 名称
false, // durable
false, // delete when unused
true, // exclusive
false, // no-wait
nil, // 参数
)
failOnError(err, "声明队列失败")
err = ch.QueueBind(
q.Name, // 队列名称
ns, // 路由键
"dsm_tasks_notify", // 交换机
false,
nil)
failOnError(err, "绑定队列失败")
msgs, err := ch.Consume(
q.Name, // 队列
"", // 消费者
true, // 自动确认
false, // 独占
false, // 不接收本地发布的消息
false, // no-wait
nil, // 参数
)
failOnError(err, "注册消费者失败")
for {
select {
case d := <-msgs:
err = c.WriteMessage(websocket.TextMessage, d.Body)
if err != nil {
log.Println("写入消息失败:", err)
break
}
case <-r.Context().Done():
log.Println("连接断开")
return
}
}
}
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
}
func main() {
var err error
conn, err = amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "连接RabbitMQ失败")
defer conn.Close()
http.HandleFunc("/watch", watch)
log.Fatal(http.ListenAndServe(addr, nil))
}
希望对你有帮助!
英文:
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.
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
"github.com/streadway/amqp"
)
var (
addr = "localhost:9999"
upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
)
var conn *amqp.Connection
func watch(w http.ResponseWriter, r *http.Request) {
ns := r.URL.Query().Get("ns")
if ns == "" {
return
}
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
ch, err := conn.Channel()
failOnError(err, "Failed to open a channel")
defer ch.Close()
err = ch.ExchangeDeclare(
"notify", // name
"fanout", // type
true, // durable
false, // auto-deleted
false, // internal
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare an exchange")
q, err := ch.QueueDeclare(
"", // name
false, // durable
false, // delete when usused
true, // exclusive
false, // no-wait
nil, // arguments
)
failOnError(err, "Failed to declare a queue")
err = ch.QueueBind(
q.Name, // queue name
ns, // routing key
"dsm_tasks_notify", // exchange
false,
nil)
failOnError(err, "Failed to bind a queue")
msgs, err := ch.Consume(
q.Name, // queue
"", // consumer
true, // auto-ack
false, // exclusive
false, // no-local
false, // no-wait
nil, // args
)
failOnError(err, "Failed to register a consumer")
for {
select {
case d := <-msgs:
err = c.WriteMessage(websocket.TextMessage, d.Body)
if err != nil {
log.Println("write:", err)
break
}
case <-r.Context().Done():
log.Println("Disconnect")
return
}
}
}
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
}
func main() {
var err error
conn, err = amqp.Dial("amqp://guest:guest@localhost:5672/")
failOnError(err, "Failed to connect to RabbitMQ")
defer conn.Close()
http.HandleFunc("/watch", watch)
log.Fatal(http.ListenAndServe(addr, nil))
}
答案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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论