Build a real-time chat application in Go by leveraging the net/http package for HTTP/WebSocket upgrades and the gorilla/websocket library to manage persistent, full-duplex connections between clients and a central server. The core architecture involves a hub that broadcasts messages to all connected clients while maintaining a slice of active connections for efficient message distribution.
Here is a minimal, working example using the standard library for the server and gorilla/websocket for the client-side upgrade:
server.go
package main
import (
"log"
"net/http"
"sync"
"github.com/gorilla/websocket"
)
var (
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
}
clients = make(map[*websocket.Conn]bool)
mu sync.Mutex
)
func handleConnections(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
mu.Lock()
clients[conn] = true
mu.Unlock()
defer func() {
mu.Lock()
delete(clients, conn)
mu.Unlock()
}()
for {
_, message, err := conn.ReadMessage()
if err != nil {
break
}
broadcast(message)
}
}
func broadcast(message []byte) {
mu.Lock()
defer mu.Unlock()
for client := range clients {
if err := client.WriteMessage(websocket.TextMessage, message); err != nil {
client.Close()
}
}
}
func main() {
http.HandleFunc("/ws", handleConnections)
log.Println("Server starting on :8080")
http.ListenAndServe(":8080", nil)
}
client.html
<script>
const socket = new WebSocket("ws://localhost:8080/ws");
socket.onmessage = function(event) {
console.log("Received: " + event.data);
};
socket.onopen = function() {
socket.send("Hello from client!");
};
</script>
Run the server with go run server.go. This setup handles the WebSocket handshake, maintains a thread-safe map of active connections, and broadcasts incoming messages to all connected peers immediately. For production, you should add authentication, rate limiting, and a persistent message store (like Redis or a database) to handle history and scale beyond a single process.