Gorilla WebSocket server - Handle client disconnected

Hi all. I have the following code using Gorilla implementing a WebSocket server, this websocket will check user messages i the database and if it finds unread messages, it’ll deliver those messages to that user. All should happen inside msgTicker.C, the problem is that when I close the client page, it still executes the ticker a couple times before stops. How can I know IMMEDIATELY when the client has been disconnected or closed the page? Below my code;

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
)

const (
	// Time allowed to write the file to the client.
	writeWait = 10 * time.Second

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

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

	// Poll file for changes with this period.
	msgPeriod = 10 * time.Second
)

var (
	upgrader = websocket.Upgrader{
		ReadBufferSize:  1024,
		WriteBufferSize: 1024,
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}
)

func reader(ws *websocket.Conn) {
	defer ws.Close()
	ws.SetReadLimit(512)
	ws.SetReadDeadline(time.Now().Add(pongWait))
	ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
	for {
		_, _, err := ws.ReadMessage()
		if err != nil {
			break
		}
	}
}

func writer(ws *websocket.Conn, idUsuario string) {
	pingTicker := time.NewTicker(pingPeriod)
	msgTicker := time.NewTicker(msgPeriod)
	defer func() {
		pingTicker.Stop()
		msgTicker.Stop()
		ws.Close()
	}()
	for {
		select {
		case <-msgTicker.C:
			var p []byte
			//var err error

			//VERIFICAR AS MENSAGENS DO USUÁRIO AQUI NO BANCO PELO idUsuario.
			//NA VARIÁVEL "p" VAI O PACOTE PARA O CLIENTE.

			p = nil //só para teste, tirar depois.
			//p = []byte("TESTE CONEXÃO WEBSOCKET!! IDUSUARIO: " + idUsuario)

			println("TESTE CONEXÃO.")

			if p != nil {
				ws.SetWriteDeadline(time.Now().Add(writeWait))
				if err := ws.WriteMessage(websocket.TextMessage, p); err == nil {
					//pacote enviado, dar update no banco aqui e setar as mensagens como recebido = 1
				} else {
					return
				}
			}
		case <-pingTicker.C:
			ws.SetWriteDeadline(time.Now().Add(writeWait))
			if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				return
			}
		}
	}
}

func wswebverificamensagensusuario(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		if _, ok := err.(websocket.HandshakeError); !ok {
			log.Println(err)
		}
		println(err.Error())
		return
	}

	go writer(ws, r.FormValue("idusuario"))
	reader(ws)
}

In r of wswebverificamensagensusuario you should have Context. Maybe you can propagate it further (argument to writer) and check it.

1 Like

No that won’t work because this function is ended soon, my code is executed inside a go routine. This is a WebSocket. Are you sure I can do that way with WebSockets?

No :slight_smile: But you pass r and w to the the socket (connection) so it is worth a try.

But you are probably right, these two connections are independant. Maybe you can check hearthbeat like here:

In Conn struct (ws) you have methods like PingHandler, PongHandler, CloseHandler, you can probably use them to do connection check.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.