WebSocket library for fasthttp. And now for net/http too.
Checkout examples to inspire yourself.
Other WebSocket packages does not allow concurrent Read/Write operations and does not provide low level access to WebSocket packet crafting.
Following the fasthttp philosophy this library tries to avoid extra-allocations while providing concurrent access to Read/Write operations and stable API to be used in production allowing low level access to the WebSocket frames.
To see an example of what this package CAN do that others DONT checkout this or this examples.
Okay. It's easy. You have an Upgrader which is used to upgrade your connection. You must specify the Handler to handle the request.
If you just want a WebSocket connection and don't want to be a WebSocket expert you can just use Upgrade function passing the handler.
package main
import (
"fmt"
"github.com/valyala/fasthttp"
"github.com/xenking/fastws"
)
func main() {
fasthttp.ListenAndServe(":8080", fastws.Upgrade(wsHandler))
}
func wsHandler(conn *fastws.Conn) {
fmt.Fprintf(conn, "Hello world")
}
After this point you can handle your awesome WebSocket connection. The connection is automatically closed by fastws when you exit your handler. YES! You are able to close your connection if you want to send a close message to the peer.
If you are looking for a low level usage of the library you can use the Frame structure to handle frame by frame in a WebSocket connection. Also you can use Conn.ReadFrame or Conn.NextFrame to read frame by frame from your peers.
package main
import (
"fmt"
"github.com/valyala/fasthttp"
"github.com/xenking/fastws"
)
func main() {
fasthttp.ListenAndServe(":8080", fastws.Upgrade(wsHandler))
}
func wsHandler(conn *fastws.Conn) {
fmt.Fprintf(conn, "Hello world")
fr, err := conn.NextFrame()
if err != nil {
panic(err)
}
fmt.Printf("Received: %s\n", fr.Payload())
fastws.ReleaseFrame(fr)
}
All of the Conn functions are safe-concurrent. Ready to be used from different goroutines. If you want to deal with the frames you can either use Conn or your own net.Conn, but remember to manage concurrency when using a net.Conn
Just call Dial.
package main
import (
"fmt"
"github.com/xenking/fastws"
)
func main() {
conn, err := fastws.Dial("ws://localhost:8080/ws")
if err != nil {
fmt.Println(err)
}
conn.WriteString("Hello")
}
Features | fastws | Gorilla | Nhooyr | gowabs |
---|---|---|---|---|
Concurrent R/W | Yes | No | No. Only writes | No |
Passes Autobahn Test Suite | Mostly | Yes | Yes | Mostly |
Receive fragmented message | Yes | Yes | Yes | Yes |
Send close message | Yes | Yes | Yes | Yes |
Send pings and receive pongs | Yes | Yes | Yes | Yes |
Get the type of a received data message | Yes | Yes | Yes | Yes |
Compression Extensions | On development | Experimental | Yes | No (?) |
Read message using io.Reader | Not planned | Yes | No | No (?) |
Write message using io.WriteCloser | Not planned | Yes | No | No (?) |
Fastws:
$ go test -bench=Fast -benchmem -benchtime=10s
Benchmark1000FastClientsPer10Messages-8 225367248 52.6 ns/op 0 B/op 0 allocs/op
Benchmark1000FastClientsPer100Messages-8 1000000000 5.48 ns/op 0 B/op 0 allocs/op
Benchmark1000FastClientsPer1000Messages-8 1000000000 0.593 ns/op 0 B/op 0 allocs/op
Benchmark100FastMsgsPerConn-8 1000000000 7.38 ns/op 0 B/op 0 allocs/op
Benchmark1000FastMsgsPerConn-8 1000000000 0.743 ns/op 0 B/op 0 allocs/op
Benchmark10000FastMsgsPerConn-8 1000000000 0.0895 ns/op 0 B/op 0 allocs/op
Benchmark100000FastMsgsPerConn-8 1000000000 0.0186 ns/op 0 B/op 0 allocs/op
Gorilla:
$ go test -bench=Gorilla -benchmem -benchtime=10s
Benchmark1000GorillaClientsPer10Messages-8 128621386 97.5 ns/op 86 B/op 1 allocs/op
Benchmark1000GorillaClientsPer100Messages-8 1000000000 11.0 ns/op 8 B/op 0 allocs/op
Benchmark1000GorillaClientsPer1000Messages-8 1000000000 1.12 ns/op 0 B/op 0 allocs/op
Benchmark100GorillaMsgsPerConn-8 849490059 14.0 ns/op 8 B/op 0 allocs/op
Benchmark1000GorillaMsgsPerConn-8 1000000000 1.42 ns/op 0 B/op 0 allocs/op
Benchmark10000GorillaMsgsPerConn-8 1000000000 0.143 ns/op 0 B/op 0 allocs/op
Benchmark100000GorillaMsgsPerConn-8 1000000000 0.0252 ns/op 0 B/op 0 allocs/op
Nhooyr:
$ go test -bench=Nhooyr -benchmem -benchtime=10s
Benchmark1000NhooyrClientsPer10Messages-8 121254158 114 ns/op 87 B/op 1 allocs/op
Benchmark1000NhooyrClientsPer100Messages-8 1000000000 11.1 ns/op 8 B/op 0 allocs/op
Benchmark1000NhooyrClientsPer1000Messages-8 1000000000 1.19 ns/op 0 B/op 0 allocs/op
Benchmark100NhooyrMsgsPerConn-8 845071632 15.1 ns/op 8 B/op 0 allocs/op
Benchmark1000NhooyrMsgsPerConn-8 1000000000 1.47 ns/op 0 B/op 0 allocs/op
Benchmark10000NhooyrMsgsPerConn-8 1000000000 0.157 ns/op 0 B/op 0 allocs/op
Benchmark100000NhooyrMsgsPerConn-8 1000000000 0.0251 ns/op 0 B/op 0 allocs/op
Gobwas:
$ go test -bench=Gobwas -benchmem -benchtime=10s
Benchmark1000GobwasClientsPer10Messages-8 98497042 106 ns/op 86 B/op 1 allocs/op
Benchmark1000GobwasClientsPer100Messages-8 1000000000 13.4 ns/op 8 B/op 0 allocs/op
Benchmark1000GobwasClientsPer1000Messages-8 1000000000 1.19 ns/op 0 B/op 0 allocs/op
Benchmark100GobwasMsgsPerConn-8 833576667 14.6 ns/op 8 B/op 0 allocs/op
Benchmark1000GobwasMsgsPerConn-8 1000000000 1.46 ns/op 0 B/op 0 allocs/op
Benchmark10000GobwasMsgsPerConn-8 1000000000 0.156 ns/op 0 B/op 0 allocs/op
Benchmark100000GobwasMsgsPerConn-8 1000000000 0.0262 ns/op 0 B/op 0 allocs/op
The following stress test were performed without timeouts:
Executing tcpkali --ws -c 100 -m 'hello world!!13212312!' -r 10k localhost:8081
the tests shows the following:
Fastws:
Total data sent: 267.4 MiB (280416485 bytes)
Total data received: 229.2 MiB (240330760 bytes)
Bandwidth per channel: 4.164⇅ Mbps (520.5 kBps)
Aggregate bandwidth: 192.172↓, 224.225↑ Mbps
Packet rate estimate: 153966.7↓, 47866.8↑ (1↓, 1↑ TCP MSS/op)
Test duration: 10.0048 s.
Gorilla:
Total data sent: 267.6 MiB (280594916 bytes)
Total data received: 165.8 MiB (173883303 bytes)
Bandwidth per channel: 3.632⇅ Mbps (454.0 kBps)
Aggregate bandwidth: 138.973↓, 224.260↑ Mbps
Packet rate estimate: 215158.9↓, 74635.5↑ (1↓, 1↑ TCP MSS/op)
Test duration: 10.0096 s.
Nhooyr: (Don't know why is that low)
Total data sent: 234.3 MiB (245645988 bytes)
Total data received: 67.7 MiB (70944682 bytes)
Bandwidth per channel: 2.532⇅ Mbps (316.5 kBps)
Aggregate bandwidth: 56.740↓, 196.461↑ Mbps
Packet rate estimate: 92483.9↓, 50538.6↑ (1↓, 1↑ TCP MSS/op)
Test duration: 10.0028 s
Gobwas:
Total data sent: 267.6 MiB (280591457 bytes)
Total data received: 169.5 MiB (177693000 bytes)
Bandwidth per channel: 3.664⇅ Mbps (458.0 kBps)
Aggregate bandwidth: 142.080↓, 224.356↑ Mbps
Packet rate estimate: 189499.0↓, 66535.5↑ (1↓, 1↑ TCP MSS/op)
Test duration: 10.0052 s.
The source files are in this folder.