Minimal and idiomatic WebSocket library for Go
websocket
websocket is a minimal and idiomatic WebSocket library for Go.
Install
go get github.com/coder/websocket
[!NOTE]
Coder now maintains this project as explained in this blog post.
We're grateful to nhooyr for authoring and maintaining this project from
2019 to 2024.
Highlights
- Minimal and idiomatic API
- First class context.Context support
- Fully passes the WebSocket autobahn-testsuite
- Zero dependencies
- JSON helpers in the wsjson subpackage
- Zero alloc reads and writes
- Concurrent writes
- Close handshake
- net.Conn wrapper
- Ping pong API
- RFC 7692 permessage-deflate compression
- CloseRead helper for write only connections
- Compile to Wasm
Roadmap
See GitHub issues for minor issues but the major future enhancements are:
- [ ] Perfect examples #217
- [ ] wstest.Pipe for in memory testing #340
- [ ] Ping pong heartbeat helper #267
- [ ] Ping pong instrumentation callbacks #246
- [ ] Graceful shutdown helpers #209
- [ ] Assembly for WebSocket masking #16
Examples
For a production quality example that demonstrates the complete API, see the echo example.
For a full stack example, see the chat example.
Server
http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
c, err := websocket.Accept(w, r, nil)
if err != nil {
// ...
}
defer c.CloseNow()
// Set the context as needed. Use of r.Context() is not recommended // to avoid surprising behavior (see http.Hijacker). ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel()
var v any err = wsjson.Read(ctx, c, &v) if err != nil { // ... }
log.Printf("received: %v", v)
c.Close(websocket.StatusNormalClosure, "") })
Client
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
c, _, err := websocket.Dial(ctx, "ws://localhost:8080", nil) if err != nil { // ... } defer c.CloseNow()
err = wsjson.Write(ctx, c, "hi") if err != nil { // ... }
c.Close(websocket.StatusNormalClosure, "")
Comparison
gorilla/websocket
Advantages of gorilla/websocket:
- Mature and widely used
- Prepared writes
- Configurable buffer sizes
- Minimal and idiomatic API
- net.Conn wrapper
- Zero alloc reads and writes (gorilla/websocket#535)
- Full context.Context support
- Dial uses net/http.Client
- Concurrent writes
- Close handshake (gorilla/websocket#448)
- Idiomatic ping pong API
- Can target Wasm (gorilla/websocket#432)
- Transparent message buffer reuse with wsjson subpackage
- 1.75x faster WebSocket masking implementation in pure Go
- Full permessage-deflate compression extension support
- CloseRead helper for write only connections (gorilla/websocket#492)
golang.org/x/net/websocket
golang.org/x/net/websocket is deprecated. See golang/go/issues/18152.
The net.Conn can help in transitioning to github.com/coder/websocket.
gobwas/ws
gobwas/ws has an extremely flexible API that allows it to be used in an event driven style for performance. See the author's blog post.
However it is quite bloated. See https://pkg.go.dev/github.com/gobwas/ws
When writing idiomatic Go, github.com/coder/websocket will be faster and easier to use.
lesismal/nbio
lesismal/nbio is similar to gobwas/ws in that the API is event driven for performance reasons.
However it is quite bloated. See https://pkg.go.dev/github.com/lesismal/nbio
When writing idiomatic Go, github.com/coder/websocket will be faster and easier to use.