Golang is really great when it comes to network programming. Maintaining web sockets, and scaling them, comes very easy with Go.
In this article, we will be creating a WebSocket server to receive messages from clients. After that, we will also explore broadcasting messages to all clients.
We will be using the following packages for creating WebSockets:
golang.org/x/net/websocket - This package implements client and server for WebSocket protocol
net/http - For creating a server
So, let's begin.
Importing libraries
package main
import (
"fmt"
"io"
"net/http"
"golang.org/x/net/websocket"
)
Creating Interface for Server
The server needs to persist the address of all clients. In case any connection information is lost, the server won't be able to connect to that client. Here we are using a map to persist all connections.
type Server struct {
coons map[*websocket.Conn]bool
}
func NewServer() *Server {
return &Server{
coons: make(map[*websocket.Conn]bool),
}
}
Handler for Connection requests
Here we are doing two jobs. When we get the connection request we will persist that connection and start reading from that connection in a loop.
func (s *Server) handleWS(ws *websocket.Conn) {
fmt.Print("New Incoming Connection", ws.RemoteAddr())
s.coons[ws] = true
s.readLoop(ws)
}
func (s *Server) readLoop(ws *websocket.Conn) {
buff := make([]byte, 1024) /// creating a buffer here to read from client
for {
n, err := ws.Read(buff) //// blocking call to read fron client
if err != nil {
if err == io.EOF { // is client has sent a signal to close the connection
break
}
fmt.Println("Read error")
continue
}
msg := buff[:n]
fmt.Println(string(msg))
ws.Write([]byte("thank you for the message"))
}
}
Initiating Server
We are starting the server on port 3000. For every request matching path /ws, the request will be routed to the handler we just created.
func main() {
server := NewServer()
http.Handle("/ws", websocket.Handler(server.handleWS))
http.ListenAndServe(":3000", nil)
}
Broadcast message
Broadcasting message to clients is fairly easy. Just get all the connections that we have persisted and send data to these clients.
func (s *Server) handleWS(ws *websocket.Conn) {
fmt.Print("New Incoming Connection", ws.RemoteAddr())
s.broadCastMessage() // whenever a new client has joined broadcast message to all the other clients
s.coons[ws] = true
s.readLoop(ws)
}
func (s *Server) broadCastMessage() {
broadCastMessage := []byte("A new peer has joined the group")
for key, _ := range s.coons {
connection := key
connection.Write(broadCastMessage)
}
}
Testing
This can be easily tested via any socket client. I prefer to test it using Javascript. Just go to the Chrome console and create a web socket to connect to our server.
let socket = new WebSocket("ws://localhost:3000/ws"); // connecting to socket
/// adding listener on any message received
socket.onMessage = (event) => console.log(`Received data: ${event.data}`)
socket.send("Hi I am here"); /// sending data to server
Happy Coding ๐ค