Table of Contents
- Overview
- Prerequisites
- Setting Up
- Creating the Websocket Server
- Handling Incoming Connections
- Sending and Receiving Messages
- Testing the Server
- Conclusion
Overview
In this tutorial, we will learn how to implement a concurrent websocket server in Go. Websockets provide a persistent connection between a client and a server, allowing real-time communication. By the end of this tutorial, you will be able to create a websocket server that can handle multiple client connections concurrently.
Prerequisites
To follow this tutorial, you should have a basic understanding of the Go programming language. Familiarity with networking concepts and concepts related to concurrent programming would be helpful but not necessary.
Setting Up
Before we start, make sure you have Go installed on your machine. You can download it from the official website and follow the installation instructions for your operating system.
Creating the Websocket Server
Let’s start by creating a new Go module called “websocket-server”.
$ go mod init websocket-server
Next, create a new file called “main.go” and open it in your preferred code editor.
$ touch main.go
Add the following code to “main.go”:
package main
import (
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
func main() {
http.HandleFunc("/ws", handleWebsocketConnection)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func handleWebsocketConnection(w http.ResponseWriter, r *http.Request) {
// Upgrade HTTP connection to websocket
upgrader := websocket.Upgrader{}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Failed to upgrade connection:", err)
return
}
// Start a new goroutine to handle the connection
go handleMessages(conn)
}
func handleMessages(conn *websocket.Conn) {
defer conn.Close()
for {
// Read incoming message from the websocket connection
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Failed to read message:", err)
break
}
// Print the received message
fmt.Println("Received message:", string(message))
// Send a response back to the client
response := []byte("Server received your message")
err = conn.WriteMessage(websocket.TextMessage, response)
if err != nil {
log.Println("Failed to send response:", err)
break
}
}
}
In the code above, we import the necessary packages, including the “gorilla/websocket” package for WebSocket functionality. We define the main
function, which registers a handler for the “/ws” path and starts the HTTP server. The handleWebsocketConnection
function upgrades the HTTP connection to a WebSocket connection and starts a new goroutine to handle the connection. The handleMessages
function reads incoming messages from the WebSocket connection and sends a response back to the client.
Handling Incoming Connections
To handle incoming WebSocket connections, we need to implement the handleWebsocketConnection
function. This function is called when a client requests a WebSocket connection to the “/ws” path.
Inside the handleWebsocketConnection
function, add the following code:
func handleWebsocketConnection(w http.ResponseWriter, r *http.Request) {
// Upgrade HTTP connection to websocket
upgrader := websocket.Upgrader{}
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("Failed to upgrade connection:", err)
return
}
// Start a new goroutine to handle the connection
go handleMessages(conn)
}
In the code above, we use the websocket.Upgrader
struct to upgrade the HTTP connection to a WebSocket connection. We pass the Upgrader
along with the response writer and the request to the Upgrade
function. If the upgrade is successful, we start a new goroutine to handle the WebSocket connection.
Sending and Receiving Messages
To handle sending and receiving messages, we need to implement the handleMessages
function. This function reads incoming messages from the WebSocket connection and sends a response back to the client.
Inside the handleMessages
function, add the following code:
func handleMessages(conn *websocket.Conn) {
defer conn.Close()
for {
// Read incoming message from the websocket connection
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Failed to read message:", err)
break
}
// Print the received message
fmt.Println("Received message:", string(message))
// Send a response back to the client
response := []byte("Server received your message")
err = conn.WriteMessage(websocket.TextMessage, response)
if err != nil {
log.Println("Failed to send response:", err)
break
}
}
}
In the code above, we use a loop to continuously read incoming messages from the WebSocket connection. We print the received message and send a response back to the client.
Testing the Server
To test our WebSocket server, we can use a WebSocket client such as “wscat” (WebSocket cat). If you don’t have “wscat” installed, you can install it using NPM:
$ npm install -g wscat
Start the server by running the following command:
$ go run main.go
In a separate terminal window, connect to the server using “wscat”:
$ wscat -c ws://localhost:8080/ws
You can now send messages to the server and see the responses.
Conclusion
In this tutorial, we learned how to implement a concurrent WebSocket server in Go. We covered the basic setup, handling incoming connections, and sending/receiving messages using the “gorilla/websocket” package. You can further extend this server to handle more complex interactions and integrate it with other systems. Websockets are a powerful tool for real-time communication in web applications, and Go provides a convenient way to implement WebSocket servers.
Remember to check out the official Go documentation for more details on the packages and functions used in this tutorial.