Go WebSocket Server

Tech Stack: Go WebSocket gorilla/websocket
View on GitHub β†’

Overview

Bare-bones WebSocket echo server in Go. Accepts connections on /ws, reads each message, and writes the same bytes back. Useful as a starting point for anything real-time you want to layer on top β€” chat, live dashboards, pub/sub fan-out.

Runnable code lives in the repo under prototype-code/websocket-server-go/:

1
2
3
4
5
prototype-code/websocket-server-go/
β”œβ”€β”€ go.mod
β”œβ”€β”€ main.go          # echo server on :8080/ws
└── client/
    └── main.go      # sends three messages, prints the echoes

Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package main

import (
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

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

func handleWS(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("upgrade:", err)
		return
	}
	defer conn.Close()

	for {
		mt, msg, err := conn.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			return
		}
		if err := conn.WriteMessage(mt, msg); err != nil {
			log.Println("write:", err)
			return
		}
	}
}

func main() {
	http.HandleFunc("/ws", handleWS)
	log.Println("listening on :8080")
	log.Fatal(http.ListenAndServe(":8080", nil))
}

Run it

In one terminal:

1
2
cd prototype-code/websocket-server-go
go run .

In another:

1
2
cd prototype-code/websocket-server-go
go run ./client

The client sends three messages and prints each echo. The server logs every received frame and the eventual disconnect.

Or test from the browser console

1
2
3
const ws = new WebSocket('ws://localhost:8080/ws');
ws.onmessage = (e) => console.log('echo:', e.data);
ws.onopen = () => ws.send('hello');

What’s deliberately missing

  • No origin check. CheckOrigin returns true for everything β€” fine for local dev, not for production.
  • No read/write deadlines or ping-pong. Idle or half-open connections will sit forever.
  • No fan-out. Each connection is independent; messages don’t reach other clients.
  • No graceful shutdown. Ctrl-C drops in-flight connections, and the client closes its TCP socket without sending a WebSocket Close frame β€” the server logs close 1006 (abnormal closure) as a result.

Each of these is the next thing to add, depending on what you’re building.