[822] | 1 | # websocket
|
---|
| 2 |
|
---|
| 3 | [](https://pkg.go.dev/nhooyr.io/websocket)
|
---|
| 4 | [](https://nhooyrio-websocket-coverage.netlify.app)
|
---|
| 5 |
|
---|
| 6 | websocket is a minimal and idiomatic WebSocket library for Go.
|
---|
| 7 |
|
---|
| 8 | ## Install
|
---|
| 9 |
|
---|
| 10 | ```bash
|
---|
| 11 | go get nhooyr.io/websocket
|
---|
| 12 | ```
|
---|
| 13 |
|
---|
| 14 | ## Highlights
|
---|
| 15 |
|
---|
| 16 | - Minimal and idiomatic API
|
---|
| 17 | - First class [context.Context](https://blog.golang.org/context) support
|
---|
| 18 | - Fully passes the WebSocket [autobahn-testsuite](https://github.com/crossbario/autobahn-testsuite)
|
---|
| 19 | - [Single dependency](https://pkg.go.dev/nhooyr.io/websocket?tab=imports)
|
---|
| 20 | - JSON and protobuf helpers in the [wsjson](https://pkg.go.dev/nhooyr.io/websocket/wsjson) and [wspb](https://pkg.go.dev/nhooyr.io/websocket/wspb) subpackages
|
---|
| 21 | - Zero alloc reads and writes
|
---|
| 22 | - Concurrent writes
|
---|
| 23 | - [Close handshake](https://pkg.go.dev/nhooyr.io/websocket#Conn.Close)
|
---|
| 24 | - [net.Conn](https://pkg.go.dev/nhooyr.io/websocket#NetConn) wrapper
|
---|
| 25 | - [Ping pong](https://pkg.go.dev/nhooyr.io/websocket#Conn.Ping) API
|
---|
| 26 | - [RFC 7692](https://tools.ietf.org/html/rfc7692) permessage-deflate compression
|
---|
| 27 | - Compile to [Wasm](https://pkg.go.dev/nhooyr.io/websocket#hdr-Wasm)
|
---|
| 28 |
|
---|
| 29 | ## Roadmap
|
---|
| 30 |
|
---|
| 31 | - [ ] HTTP/2 [#4](https://github.com/nhooyr/websocket/issues/4)
|
---|
| 32 |
|
---|
| 33 | ## Examples
|
---|
| 34 |
|
---|
| 35 | For a production quality example that demonstrates the complete API, see the
|
---|
| 36 | [echo example](./examples/echo).
|
---|
| 37 |
|
---|
| 38 | For a full stack example, see the [chat example](./examples/chat).
|
---|
| 39 |
|
---|
| 40 | ### Server
|
---|
| 41 |
|
---|
| 42 | ```go
|
---|
| 43 | http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) {
|
---|
| 44 | c, err := websocket.Accept(w, r, nil)
|
---|
| 45 | if err != nil {
|
---|
| 46 | // ...
|
---|
| 47 | }
|
---|
| 48 | defer c.Close(websocket.StatusInternalError, "the sky is falling")
|
---|
| 49 |
|
---|
| 50 | ctx, cancel := context.WithTimeout(r.Context(), time.Second*10)
|
---|
| 51 | defer cancel()
|
---|
| 52 |
|
---|
| 53 | var v interface{}
|
---|
| 54 | err = wsjson.Read(ctx, c, &v)
|
---|
| 55 | if err != nil {
|
---|
| 56 | // ...
|
---|
| 57 | }
|
---|
| 58 |
|
---|
| 59 | log.Printf("received: %v", v)
|
---|
| 60 |
|
---|
| 61 | c.Close(websocket.StatusNormalClosure, "")
|
---|
| 62 | })
|
---|
| 63 | ```
|
---|
| 64 |
|
---|
| 65 | ### Client
|
---|
| 66 |
|
---|
| 67 | ```go
|
---|
| 68 | ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
---|
| 69 | defer cancel()
|
---|
| 70 |
|
---|
| 71 | c, _, err := websocket.Dial(ctx, "ws://localhost:8080", nil)
|
---|
| 72 | if err != nil {
|
---|
| 73 | // ...
|
---|
| 74 | }
|
---|
| 75 | defer c.Close(websocket.StatusInternalError, "the sky is falling")
|
---|
| 76 |
|
---|
| 77 | err = wsjson.Write(ctx, c, "hi")
|
---|
| 78 | if err != nil {
|
---|
| 79 | // ...
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | c.Close(websocket.StatusNormalClosure, "")
|
---|
| 83 | ```
|
---|
| 84 |
|
---|
| 85 | ## Comparison
|
---|
| 86 |
|
---|
| 87 | ### gorilla/websocket
|
---|
| 88 |
|
---|
| 89 | Advantages of [gorilla/websocket](https://github.com/gorilla/websocket):
|
---|
| 90 |
|
---|
| 91 | - Mature and widely used
|
---|
| 92 | - [Prepared writes](https://pkg.go.dev/github.com/gorilla/websocket#PreparedMessage)
|
---|
| 93 | - Configurable [buffer sizes](https://pkg.go.dev/github.com/gorilla/websocket#hdr-Buffers)
|
---|
| 94 |
|
---|
| 95 | Advantages of nhooyr.io/websocket:
|
---|
| 96 |
|
---|
| 97 | - Minimal and idiomatic API
|
---|
| 98 | - Compare godoc of [nhooyr.io/websocket](https://pkg.go.dev/nhooyr.io/websocket) with [gorilla/websocket](https://pkg.go.dev/github.com/gorilla/websocket) side by side.
|
---|
| 99 | - [net.Conn](https://pkg.go.dev/nhooyr.io/websocket#NetConn) wrapper
|
---|
| 100 | - Zero alloc reads and writes ([gorilla/websocket#535](https://github.com/gorilla/websocket/issues/535))
|
---|
| 101 | - Full [context.Context](https://blog.golang.org/context) support
|
---|
| 102 | - Dial uses [net/http.Client](https://golang.org/pkg/net/http/#Client)
|
---|
| 103 | - Will enable easy HTTP/2 support in the future
|
---|
| 104 | - Gorilla writes directly to a net.Conn and so duplicates features of net/http.Client.
|
---|
| 105 | - Concurrent writes
|
---|
| 106 | - Close handshake ([gorilla/websocket#448](https://github.com/gorilla/websocket/issues/448))
|
---|
| 107 | - Idiomatic [ping pong](https://pkg.go.dev/nhooyr.io/websocket#Conn.Ping) API
|
---|
| 108 | - Gorilla requires registering a pong callback before sending a Ping
|
---|
| 109 | - Can target Wasm ([gorilla/websocket#432](https://github.com/gorilla/websocket/issues/432))
|
---|
| 110 | - Transparent message buffer reuse with [wsjson](https://pkg.go.dev/nhooyr.io/websocket/wsjson) and [wspb](https://pkg.go.dev/nhooyr.io/websocket/wspb) subpackages
|
---|
| 111 | - [1.75x](https://github.com/nhooyr/websocket/releases/tag/v1.7.4) faster WebSocket masking implementation in pure Go
|
---|
| 112 | - Gorilla's implementation is slower and uses [unsafe](https://golang.org/pkg/unsafe/).
|
---|
| 113 | - Full [permessage-deflate](https://tools.ietf.org/html/rfc7692) compression extension support
|
---|
| 114 | - Gorilla only supports no context takeover mode
|
---|
| 115 | - We use [klauspost/compress](https://github.com/klauspost/compress) for much lower memory usage ([gorilla/websocket#203](https://github.com/gorilla/websocket/issues/203))
|
---|
| 116 | - [CloseRead](https://pkg.go.dev/nhooyr.io/websocket#Conn.CloseRead) helper ([gorilla/websocket#492](https://github.com/gorilla/websocket/issues/492))
|
---|
| 117 | - Actively maintained ([gorilla/websocket#370](https://github.com/gorilla/websocket/issues/370))
|
---|
| 118 |
|
---|
| 119 | #### golang.org/x/net/websocket
|
---|
| 120 |
|
---|
| 121 | [golang.org/x/net/websocket](https://pkg.go.dev/golang.org/x/net/websocket) is deprecated.
|
---|
| 122 | See [golang/go/issues/18152](https://github.com/golang/go/issues/18152).
|
---|
| 123 |
|
---|
| 124 | The [net.Conn](https://pkg.go.dev/nhooyr.io/websocket#NetConn) can help in transitioning
|
---|
| 125 | to nhooyr.io/websocket.
|
---|
| 126 |
|
---|
| 127 | #### gobwas/ws
|
---|
| 128 |
|
---|
| 129 | [gobwas/ws](https://github.com/gobwas/ws) has an extremely flexible API that allows it to be used
|
---|
| 130 | in an event driven style for performance. See the author's [blog post](https://medium.freecodecamp.org/million-websockets-and-go-cc58418460bb).
|
---|
| 131 |
|
---|
| 132 | However when writing idiomatic Go, nhooyr.io/websocket will be faster and easier to use.
|
---|