douyi3632 2019-08-06 13:20
浏览 66

大猩猩websocket断开被称为两次

I'm writing a Go websocket server and I want to graceful stop the connections when my server goes down. I have a map of active connections stored in the following variable:

var connections = make(map[string]*websocket.Conn)

My main function looks like this:


func main() {
    // ... stuff ....

    gracefulStop := make(chan os.Signal)
    signal.Notify(gracefulStop, syscall.SIGTERM)
    signal.Notify(gracefulStop, syscall.SIGINT)
    signal.Notify(gracefulStop, syscall.SIGQUIT)
    signal.Notify(gracefulStop, syscall.SIGKILL)
    signal.Notify(gracefulStop, syscall.SIGHUP)

    go func() {
        sig := <-gracefulStop
        log.Printf("Exiting from process due to %+v", sig)
        log.Println("Closing all websocket connections")
        for id, conn := range connections {
            closeConnection(id, conn)
        }
        os.Exit(0)
    }()

    r := mux.NewRouter()
    r.HandleFunc("/{id}", wsHandler)
    err := http.ListenAndServe(fmt.Sprintf(":%d", *argPort), r)
    if err != nil {
        log.Println("Could not start http server")
        log.Println(err)
    }
}

closeConnection does 4 things:

  • conn.Close()
  • sets conn as nil
  • removes the id from the map
  • calls an AWS Lambda function

The same function is called as a defer function inside the wsHandler function, so if a client disconnects by its own, I execute function in the handler.

It's all working nicely, except that when I ctrl+c the server my closeConnection function is called two times per client, one in the graceful stop handler and the other in the wsHandler defer function. I tried to check in my closeConnection function if the connection is still defined in connections, but it returns true both of the times.

I thought that it was due to the fact that they are called two times because they are in different goroutines, so I replaced the for loop above with just a time.Sleep(2 * time.Second), but in this case nothing happens (the closeConnection inside the wsHandler defer function is not even called). This is what I mean:

go func() {
    sig := <-gracefulStop
    log.Printf("Exiting from process due to %+v", sig)
    log.Println("Closing all websocket connections")
    // for chargeboxIdentity, conn := range connections {
    //  chargeboxDisconnected(chargeboxIdentity, conn)
    // }
    time.Sleep(2 * time.Second)
    os.Exit(0)
}()

EDIT: Here is the closeConnection function:

func closeConnection(id string, conn *websocket.Conn) {
    _, ok := connections[id]
    log.Println(ok)
    log.Printf("%s (%s) disconnected", id, conn.RemoteAddr())
    conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
    time.Sleep(300 * time.Millisecond)
    conn.Close()
    conn = nil
    delete(connections, id)

    request := LambdaPayload{ID: id}
    payload, err := json.Marshal(request)
    if err != nil {
        log.Println("Could not create payload for lambda call")
        log.Println(err)
        return
    }
    _, err = client.Invoke(&lambda.InvokeInput{FunctionName: aws.String(lambdaPrefix + "MainDisconnect"), Payload: payload})
    if err != nil {
        log.Println("Disconnect Lambda returned an error")
        log.Println(err)
    }
}

EDIT: Here's the wsHandler function:

func wsHandler(w http.ResponseWriter, r *http.Request) {
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("Could not upgrade websocket connection")
        log.Println(err)
        return
    }

    vars := mux.Vars(r)
    if !clientConnected(vars["id"], conn) {
        return
    }
    defer closeConnection(vars["id"], conn)
    for {
        msgType, msg, err := conn.ReadMessage()
        if err != nil {
            break
        }

        log.Printf("%s sent: %s", vars["id"], string(msg))

        // ... stuff ...
    }
}
  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 R语言Rstudio突然无法启动
    • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
    • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
    • ¥15 用windows做服务的同志有吗
    • ¥60 求一个简单的网页(标签-安全|关键词-上传)
    • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
    • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
    • ¥100 为什么这个恒流源电路不能恒流?
    • ¥15 有偿求跨组件数据流路径图
    • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值