WebSockets provide full-duplex communication channels over a single TCP connection. This is especially beneficial for real-time web applications, allowing efficient interaction between clients and servers. In this tutorial, we will focus on building a WebSocket server in Go that can broadcast messages to multiple connected clients.
Setting Up a WebSocket Server
First, we need to install the Gorilla WebSocket package, which is a well-maintained library in the Go ecosystem for handling WebSockets. Run the following command to install it:
go get -u github.com/gorilla/websocketCreating a Basic WebSocket Server
Let’s start by creating a main.go file, where we'll define a simple HTTP server and handle WebSocket upgrades:
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
func handleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
defer ws.Close()
for {
_, message, err := ws.ReadMessage()
if err != nil {
fmt.Println(err)
break
}
fmt.Printf("Received: %s\n", message)
}
}
func main() {
http.HandleFunc("/ws", handleConnections)
fmt.Println("HTTP server started on :8080")
http.ListenAndServe(":8080", nil)
}
Broadcasting Messages
Now that we have a basic WebSocket server set up, let’s extend it to handle broadcasting messages to all connected clients. We will maintain a list of all connected clients and loop through these to broadcast messages.
Maintaining Client Connections
We can use a map to keep track of connected clients. We update our server code as follows:
var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan []byte)
func handleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
defer ws.Close()
clients[ws] = true
for {
_, message, err := ws.ReadMessage()
if err != nil {
delete(clients, ws)
fmt.Println(err)
break
}
broadcast <- message
}
}
func handleMessages() {
for {
message := <-broadcast
for client := range clients {
err := client.WriteMessage(websocket.TextMessage, message)
if err != nil {
fmt.Println(err)
client.Close()
delete(clients, client)
}
}
}
}
func main() {
http.HandleFunc("/ws", handleConnections)
go handleMessages()
fmt.Println("HTTP server started on :8080")
http.ListenAndServe(":8080", nil)
}
With this setup, any message received from a client will be broadcast to all other connected clients. This simple server can now be scaled to support many clients simultaneously.
Testing the WebSocket Server
You can use tools like WebSocket.org Echo Test or create simple HTML with JavaScript to test your server. Here is a simple HTML file that connects to your server:
WebSocket Client
let socket = new WebSocket("ws://localhost:8080/ws");
socket.onopen = function(e) {
alert("Connection established");
socket.send("Hello Server!");
};
socket.onmessage = function(event) {
alert(`Data received from server: ${event.data}`);
};
socket.onclose = function(event) {
if (event.wasClean) {
alert(`Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
alert('Connection died');
}
};
socket.onerror = function(error) {
alert(`Error: ${error.message}`);
};
Conclusion
In this article, we learned how to implement WebSocket communication in Go, with a focus on broadcast messaging to multiple connected clients. By enhancing the server capabilities, you can develop a robust real-time web application capable of serving a myriad of use cases such as real-time chat applications, live collaboration tools, gaming, and more.