Gorilla websocket is not closing

1.2k Views Asked by At

I want to open websocket server whenever i want to and close but server does not close after writing "exit" when i go back to my main() and i try to start again it fails saying "httpHandleFunc multiple registration '/' " how do i close websocket server permanently and go back to main and start server again like switch on/off.

Another issue i am facing is client side errors with Bad Handshake when using gorilla mux as a handler.

#Server-Side Code

https://go.dev/play/p/n_I4xzOomWz

package main

import (
    "bufio"
    "flag"
    "fmt"
    "net/http"
    "os"
    "strings"
    "time"

    "github.com/gorilla/mux"
    "github.com/gorilla/websocket"
    log "github.com/sirupsen/logrus"
)

const (
    // Time allowed to write a message to the peer.
    writeWait = 10 * time.Second

    // Maximum message size allowed from peer.
    maxMessageSize = 8192

    // Time allowed to read the next pong message from the peer.
    pongWait = 60 * time.Second

    // Send pings to peer with this period. Must be less than pongWait.
    pingPeriod = (pongWait * 9) / 10

    // Time to wait before force close on connection.
    closeGracePeriod = 2 * time.Second
)

var (
    server   http.Server
    addr     = "0.0.0.0:443"
    upgrader = websocket.Upgrader{
        CheckOrigin: func(r *http.Request) bool {
            return true
        },
    }
)

func ping(ws *websocket.Conn, done chan struct{}) {
    ticker := time.NewTicker(pingPeriod)
    defer ticker.Stop()
    for {
        select {
        case <-ticker.C:
            if err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil {
                log.Println("ping:", err)
            }
        case <-done:
            return
        }
    }
}

// write message
func pumpStdout(ws *websocket.Conn, done chan struct{}) {
    defer func() {
    }()
    for {
        text := ReadInput("User220 > ")
        if text == "exit" {
            break
        }

        ws.SetWriteDeadline(time.Now().Add(writeWait))
        if err := ws.WriteMessage(websocket.TextMessage, []byte(text)); err != nil {
            ws.Close()
            log.Errorln(err)
            break
        }
    }
    close(done)

    ws.SetWriteDeadline(time.Now().Add(writeWait))
    ws.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
    time.Sleep(closeGracePeriod)
    ws.Close()
}

// receive message
func pumpStdin(ws *websocket.Conn, done chan struct{}) {
    defer ws.Close()
    ws.SetReadLimit(maxMessageSize)
    ws.SetReadDeadline(time.Now().Add(pongWait))
    ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })

    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()

    for {
        select {
        case <-done:
            break
        case <-ticker.C:
            _, message, err := ws.ReadMessage()
            if err != nil {
                ws.CloseHandler()
                err := ws.UnderlyingConn().Close()
                fmt.Println(err)
                main()
            }
            if len(message) > 0 {
                fmt.Printf("\r\n%sUser220 > ", message)
            }
        }
    }
}

func WebsocketHandle(w http.ResponseWriter, r *http.Request) {
    c, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Fatalln(err)
    }
    defer c.Close()

    stdoutDone := make(chan struct{})
    go pumpStdout(c, stdoutDone)
    go ping(c, stdoutDone)

    pumpStdin(c, stdoutDone)
}

func start_socket() {
    flag.Parse()
    log.Printf("listen at %s", addr)

    // ----------------------
    mux := mux.NewRouter()
    mux.HandleFunc("/", WebsocketHandle)
    //-----------------------

    http.HandleFunc("/", WebsocketHandle)
    server = http.Server{Addr: addr}
    log.Fatalln(server.ListenAndServe())
}

func stop_server() {
    err := server.Close()
    if err != nil {
        log.Fatalln(err)
    }
}

func ReadInput(promt string) string {
    fmt.Printf("\n%s", promt)
    reader := bufio.NewReader(os.Stdin)
    input, _ := reader.ReadString('\n')
    return strings.TrimSpace(input)
}

func main() {
    for {
        read := ReadInput("Main : ")
        switch read {
        case "start":
            start_socket()
        case "stop":
            stop_server()
        default:
            fmt.Println("Not Sure")
        }
    }
}

Client side i am just polling and writing back the same message right now.

#Client-Side Code

https://go.dev/play/p/y4nUkvMFYec

package main

import (
    "fmt"
    "net/url"

    "github.com/gorilla/websocket"
    log "github.com/sirupsen/logrus"
)

var addr = "localhost:443"

func main() {
    dial := websocket.Dialer{}

    u := url.URL{Scheme: "ws", Host: addr, Path: "/"}
    log.Printf("connecting to %s", u.String())

    c, _, err := dial.Dial(u.String(), nil)
    if err != nil {
        log.Fatalln(err)
    }
    defer c.Close()

    for {
        _, message, err := c.ReadMessage()
        if err != nil {
            log.Fatalln(err)
        }
        fmt.Println("Recevied : " + string(message))

        err = c.WriteMessage(websocket.TextMessage, message)
        if err != nil {
            log.Fatalln(err)
        }

    }
}
0

There are 0 best solutions below