'Enable message compression for WebSockets in Go
I have simple client - server websocket communication and I want to know if it's possible to enable message compression for the websockets. I am using Golang library gorila/websocket.
And there are configurations like EnableCompression bool or EnableWriteCompression(bool) method, but it does not working as expected or maybe I cannot figure out how to use it.
Expected behaviour:
I am expecting to send for example - 50kb message and to be compressed to 10-20kb or something like this. But it seems that EnableWriteCompression is not working as expected or I am not using it in the right way.
The code:
server.go:
package main
import (
"fmt"
"github.com/gorilla/websocket"
"log"
"net/http"
)
var upgrader = websocket.Upgrader{}
func socketHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
conn.EnableWriteCompression(true)
if err != nil {
log.Print("Error during upgrade:", err)
return
}
defer conn.Close()
n := 0
for n <= 10 {
messageType, message, err := conn.ReadMessage()
if err != nil {
log.Println("Error during message reading:", err)
break
}
log.Printf("Received: %s", message)
err = conn.WriteMessage(messageType, message)
if err != nil {
log.Println("Error during message writing:", err)
break
}
n++
}
}
func home(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Index Page")
}
func main() {
http.HandleFunc("/socket", socketHandler)
http.HandleFunc("/", home)
log.Fatal(http.ListenAndServe("localhost:8080", nil))
}
client.go:
// client.go
package main
import (
"log"
"os"
"os/signal"
"time"
"github.com/gorilla/websocket"
)
var done chan interface{}
var interrupt chan os.Signal
func receiveHandler(connection *websocket.Conn) {
defer close(done)
for {
_, msg, err := connection.ReadMessage()
if err != nil {
log.Println("Error in receive:", err)
return
}
log.Printf("Received: %s\n", msg)
}
}
func main() {
done = make(chan interface{}) // Channel to indicate that the receiverHandler is done
interrupt = make(chan os.Signal) // Channel to listen for interrupt signal to terminate gracefully
signal.Notify(interrupt, os.Interrupt) // Notify the interrupt channel for SIGINT
socketUrl := "ws://localhost:8080" + "/socket"
conn, _, err := websocket.DefaultDialer.Dial(socketUrl, nil)
if err != nil {
log.Fatal("Error connecting to Websocket Server:", err)
}
defer conn.Close()
go receiveHandler(conn)
// Our main loop for the client
// We send our relevant packets here
for {
select {
case <-time.After(time.Duration(1) * time.Millisecond * 1000):
conn.EnableWriteCompression(true)
conn.SetCompressionLevel(1)
err := conn.WriteMessage(websocket.TextMessage, []byte("Some message to send!"))
if err != nil {
log.Println("Error during writing to websocket:", err)
return
}
case <-interrupt:
log.Println("Received SIGINT interrupt signal. Closing all pending connections")
err := conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println(err)
return
}
select {
case <-done:
log.Println("Exiting....")
case <-time.After(time.Duration(1) * time.Second):
log.Println("Exiting....")
}
return
}
}
}
Solution 1:[1]
As per documentation:
EnableWriteCompression enables and disables write compression of subsequent text and binary messages. This function is a noop if compression was not negotiated with the peer.
You need to setup the compression on Updater and Dialer level, so that it can be negotiated during the connection upgrade:
// for server
var upgrader = websocket.Upgrader{
EnableCompression: true,
}
// for client
dialer := websocket.Dialer{
Proxy: http.ProxyFromEnvironment, // From default dialer
HandshakeTimeout: 45 * time.Second, // From default dialer
EnableCompression: true,
}
...
conn, _, err := dialer.Dial(socketUrl, nil)
Your example however will not show that the messages are compressed as this is handled by the library.
You can verify it using something like Wireshark:
Sec-WebSocket-Extensions: permessage-deflate ...
and on messages:
.1.. .... = Per-Message Compressed: True
You might also need to adjust the compression level to see the result you expect (max seems to be 9).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Szymig |
