Documentation
¶
Overview ¶
Package websocket implements RFC 6455 clients and servers with a message-oriented API.
Connections ¶
Clients use Dial. HTTP handlers use Upgrade, which requires HTTP/1.x and rejects cross-origin requests by default. Use AllowedOrigins to configure origin policy and SupportedSubprotocols to select a subprotocol.
Messages ¶
Conn.ReadMessage and Conn.WriteMessage use complete byte slices. Conn.Read and Conn.Write stream messages through scoped callbacks.
Concurrency ¶
One goroutine may read while any number write. Concurrent reads return ErrInvalidArgument. A write context bounds only writer acquisition; ReadOptions and WriteOptions bound message I/O.
Connection management ¶
The package does not read in the background. Keep a Conn.Read or Conn.ReadMessage call active for the connection's lifetime, even when the application discards data messages. Reads answer pings, process pongs and close frames, and drive keepalive.
This loop discards data messages while preserving connection management. Returning nil from the callback drains the current message:
func readUntilClosed(c *websocket.Conn, opts *websocket.ReadOptions) error {
defer c.Close()
for {
err := c.Read(opts, func(*websocket.Reader) error {
return nil
})
if err != nil {
return err
}
}
}
Conn.Shutdown sends a close frame and returns without waiting. Continue reading until a read returns an error, then call Conn.Close. Without an active read, the peer's close response is not processed and graceful shutdown cannot complete.
Closing and errors ¶
Conn.Close immediately tears down the transport, unblocking in-flight reads and writes.
Terminal read errors are sticky. Use errors.As for CloseError and errors.Is for ErrClosed, ErrTimeout, ErrProtocol, and ErrInvalidArgument. Stop the read loop on any terminal error.
A write returns ErrCloseSent while a closing handshake is in progress: stop writing data, but keep reading so the handshake completes.
Text messages ¶
Inbound text is validated as UTF-8 unless ReadOptions.SkipUTF8Validation is set. Outbound text is not validated; check untrusted text (e.g. utf8.Valid) before sending, or the peer may close the connection with 1007.
Example (Echo) ¶
A roundtrip between a server built with websocket.Upgrade and a client built with websocket.Dial. The server echoes each message back; the client sends one message and prints the echo.
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"github.com/garyburd/websocket"
)
func main() {
// Server: echo every message back to the client until it disconnects.
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c, err := websocket.Upgrade(w, r, nil)
if err != nil {
return // Upgrade has already written an error response
}
defer c.Close()
for {
data, mt, err := c.ReadMessage(nil)
if err != nil {
return
}
if err := c.WriteMessage(context.Background(), mt, nil, data); err != nil {
return
}
}
}))
defer srv.Close()
// Client: httptest serves http://, so swap in the ws:// scheme to dial.
url := "ws" + strings.TrimPrefix(srv.URL, "http")
c, _, err := websocket.Dial(context.Background(), url, nil, nil)
if err != nil {
fmt.Println("dial:", err)
return
}
defer c.Close()
if err := c.WriteMessage(context.Background(), websocket.MessageText, nil, []byte("hello")); err != nil {
fmt.Println("write:", err)
return
}
data, _, err := c.ReadMessage(nil)
if err != nil {
fmt.Println("read:", err)
return
}
fmt.Printf("%s\n", data)
}
Output: hello
Example (Json) ¶
The package has no JSON helpers; use encoding/json directly over the streaming websocket.Writer and websocket.Reader. Sending encodes into the writer; receiving decodes from the reader within the read callback. The server here decodes each message and replies with a JSON message of its own.
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"github.com/garyburd/websocket"
)
func main() {
type message struct {
Greeting string `json:"greeting"`
N int `json:"n"`
}
// Server: decode each message, then reply with a JSON message.
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
c, err := websocket.Upgrade(w, r, nil)
if err != nil {
return // Upgrade has already written an error response
}
defer c.Close()
for {
var in message
err := c.Read(nil, func(rd *websocket.Reader) error {
return json.NewDecoder(rd).Decode(&in)
})
if err != nil {
return
}
reply := message{Greeting: "hi " + in.Greeting, N: in.N + 1}
err = c.Write(context.Background(), websocket.MessageText, nil, func(wr *websocket.Writer) error {
return json.NewEncoder(wr).Encode(reply)
})
if err != nil {
return
}
}
}))
defer srv.Close()
url := "ws" + strings.TrimPrefix(srv.URL, "http")
c, _, err := websocket.Dial(context.Background(), url, nil, nil)
if err != nil {
fmt.Println("dial:", err)
return
}
defer c.Close()
// Send: encode a value as one text message.
err = c.Write(context.Background(), websocket.MessageText, nil, func(w *websocket.Writer) error {
return json.NewEncoder(w).Encode(message{Greeting: "there", N: 1})
})
if err != nil {
fmt.Println("write:", err)
return
}
// Receive: decode the reply into a value.
var in message
err = c.Read(nil, func(r *websocket.Reader) error {
return json.NewDecoder(r).Decode(&in)
})
if err != nil {
fmt.Println("read:", err)
return
}
fmt.Printf("%s %d\n", in.Greeting, in.N)
}
Output: hi there 2
Index ¶
- Variables
- func AllowedOrigins(allowSameHost bool, patterns ...string) func(*http.Request) bool
- func ParseOrigin(r *http.Request) (*url.URL, error)
- func SupportedSubprotocols(supported ...string) func(*http.Request) string
- type CloseCode
- type CloseError
- type Conn
- func (c *Conn) Close() error
- func (c *Conn) NetConn() net.Conn
- func (c *Conn) Read(opts *ReadOptions, fn func(r *Reader) error) error
- func (c *Conn) ReadMessage(opts *ReadOptions) ([]byte, MessageType, error)
- func (c *Conn) Shutdown(code CloseCode, reason string) error
- func (c *Conn) Subprotocol() string
- func (c *Conn) Write(ctx context.Context, mt MessageType, opts *WriteOptions, ...) error
- func (c *Conn) WriteMessage(ctx context.Context, mt MessageType, opts *WriteOptions, data []byte) error
- type DialOptions
- type MessageType
- type ReadOptions
- type Reader
- type UpgradeOptions
- type WriteOptions
- type Writer
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrClosed reports local teardown by [Conn.Close], [Reader.Abort], or a // panicking callback. A timed-out [Conn.Shutdown] reports [ErrTimeout]. ErrClosed = errors.New("websocket: connection closed") // ErrTimeout reports a liveness or I/O deadline failure. ErrTimeout = errors.New("websocket: timeout") // ErrProtocol reports a peer protocol violation. ErrProtocol = errors.New("websocket: protocol error") // ErrBadHandshake reports a rejected opening handshake. [Dial] and [Upgrade] // wrap it with details. ErrBadHandshake = errors.New("websocket: bad handshake") // ErrCloseSent reports a data write attempted after this endpoint sent a // close frame. ErrCloseSent = errors.New("websocket: cannot write after close") // ErrInvalidArgument reports a rejected argument or option. The connection // remains usable. ErrInvalidArgument = errors.New("websocket: invalid argument") )
Functions ¶
func AllowedOrigins ¶
AllowedOrigins returns an origin check using case-insensitive path.Match patterns. Patterns containing "://" match scheme://host; others match only the host. allowSameHost accepts an Origin host equal to the request Host. An absent Origin is accepted.
Examples:
AllowedOrigins(true, "*.example.com") // request host, or any host under example.com AllowedOrigins(false, "https://app.example.com") // exactly this scheme and host AllowedOrigins(false, "https://*.example.com:443") // scheme + host + port
AllowedOrigins panics on a malformed pattern.
func ParseOrigin ¶
ParseOrigin parses the request Origin. It returns (nil, nil) when the header is absent and an error when it is malformed or has no host.
Types ¶
type CloseCode ¶
type CloseCode int
CloseCode is an RFC 6455 close status code.
CloseNoStatusReceived and CloseAbnormalClosure are receive-only.
const ( CloseNormalClosure CloseCode = 1000 CloseGoingAway CloseCode = 1001 CloseProtocolError CloseCode = 1002 CloseUnsupportedData CloseCode = 1003 CloseInvalidData CloseCode = 1007 ClosePolicyViolation CloseCode = 1008 CloseMessageTooBig CloseCode = 1009 CloseInternalError CloseCode = 1011 CloseNoStatusReceived CloseCode = 1005 CloseAbnormalClosure CloseCode = 1006 )
type CloseError ¶
type CloseError struct {
// Code is the peer status, [CloseNoStatusReceived], or
// [CloseAbnormalClosure].
Code CloseCode
// Text is the UTF-8 close reason.
Text string
}
CloseError reports a peer close. Use errors.As to inspect Code and Text. CloseAbnormalClosure means the transport ended without a close frame.
Example ¶
A read loop ends on the first error. Use errors.As to recover the peer's close code and reason from a websocket.CloseError; a websocket.CloseAbnormalClosure code means the peer vanished without sending a close message. A local websocket.Conn.Close reports websocket.ErrClosed, and other failures (timeouts, protocol errors) end the loop the same way.
package main
import (
"errors"
"log"
"github.com/garyburd/websocket"
)
func main() {
var c *websocket.Conn // obtained from websocket.Dial or websocket.Upgrade
defer c.Close()
for {
_, _, err := c.ReadMessage(nil)
if err == nil {
continue // ... handle the message ...
}
var ce *websocket.CloseError
switch {
case errors.As(err, &ce):
if ce.Code == websocket.CloseAbnormalClosure {
log.Print("peer vanished without a close message")
} else {
log.Printf("peer closed: code=%s reason=%q", ce.Code, ce.Text)
}
case errors.Is(err, websocket.ErrClosed):
log.Print("connection closed locally")
default:
log.Printf("connection failed: %v", err)
}
return
}
}
Output:
func (*CloseError) Error ¶
func (e *CloseError) Error() string
Error formats the close code and reason.
type Conn ¶
type Conn struct {
// contains filtered or unexported fields
}
Conn is a WebSocket connection created by Dial or Upgrade. One goroutine may read while any number of goroutines write concurrently.
func Dial ¶
func Dial(ctx context.Context, rawURL string, opts *DialOptions, header http.Header) (*Conn, *http.Response, error)
Dial opens a WebSocket connection. header may contain application headers such as Origin, Cookie, and Authorization.
Dial rejects Sec-WebSocket-* headers, which it manages. Configure subprotocols through DialOptions.Subprotocols.
ctx bounds only the handshake. Use Conn.Shutdown, Conn.Close, ReadOptions, and WriteOptions after Dial returns.
Dial does not follow redirects. A response other than 101 returns ErrBadHandshake and the response with up to DialOptions.ResponseBodyLimit body bytes. On success, the Conn owns the response body. The caller need not close either returned body.
func Upgrade ¶
func Upgrade(w http.ResponseWriter, r *http.Request, opts *UpgradeOptions) (*Conn, error)
Upgrade accepts a WebSocket handshake and takes ownership of the underlying HTTP/1.x connection.
On failure, Upgrade writes an HTTP error and returns ErrBadHandshake. On success, the returned Conn owns w; the handler must not use w again.
func (*Conn) Close ¶
Close immediately closes the transport and unblocks active reads and writes. It is concurrent-safe and idempotent. Use Conn.Shutdown first for a graceful close.
func (*Conn) NetConn ¶
NetConn returns the underlying network connection, or nil when unavailable.
The Conn owns the result. Do not read, write, close, or set deadlines on it.
func (*Conn) Read ¶
func (c *Conn) Read(opts *ReadOptions, fn func(r *Reader) error) error
Read passes the next message to fn. The Reader is valid only during fn; unread payload is discarded afterward unless Reader.Abort is called.
An fn error is returned unchanged, so applications can match their own errors with errors.Is or errors.As; unless fn failed a read or called Reader.Abort, the connection remains usable. ErrInvalidArgument (invalid options or a concurrent read; reads are single-goroutine) also leaves the connection untouched. Any other error is terminal and sticky: every later Read returns it, so stop the read loop.
A panic in fn tears down the connection and propagates.
Example (WriteOnly) ¶
An application that only sends data must still keep a read outstanding, so the package can answer the peer's pings and observe its close. Run a discarding read loop in its own goroutine alongside the writer; the keepalive options on the read detect a peer that has gone away.
package main
import (
"context"
"time"
"github.com/garyburd/websocket"
)
func main() {
var c *websocket.Conn // obtained from websocket.Dial or websocket.Upgrade
// Discard inbound data, but let the package handle control frames and surface
// the peer's close. The first error ends the loop and closes the connection.
go func() {
opts := &websocket.ReadOptions{
KeepaliveInterval: 30 * time.Second,
KeepaliveTimeout: 10 * time.Second,
MatchPong: true,
}
for {
if err := c.Read(opts, func(*websocket.Reader) error { return nil }); err != nil {
c.Close()
return
}
}
}()
// Send the time once a second until the connection goes away.
tick := time.NewTicker(time.Second)
defer tick.Stop()
for range tick.C {
msg := []byte(time.Now().Format(time.RFC3339))
if err := c.WriteMessage(context.Background(), websocket.MessageText, nil, msg); err != nil {
return // the read goroutine has already closed the connection
}
}
}
Output:
func (*Conn) ReadMessage ¶
func (c *Conn) ReadMessage(opts *ReadOptions) ([]byte, MessageType, error)
ReadMessage reads and returns one complete message.
func (*Conn) Shutdown ¶
Shutdown sends a close frame and returns without waiting for the response. Continue reading, then call Conn.Close. A message the peer is still sending may be cut off; read any inbound message you need to completion first.
An invalid code or invalid UTF-8 in reason returns ErrInvalidArgument. The reason is truncated to 123 bytes at a rune boundary.
DialOptions.ShutdownTimeout or UpgradeOptions.ShutdownTimeout bounds both sending and waiting. Expiry tears down the connection with ErrTimeout. Shutdown is safe for concurrent use and is a no-op when closing has begun.
Example ¶
To close gracefully, call websocket.Conn.Shutdown to send the close message, then keep reading until the read loop drains the peer's echo and returns an error, and finally call websocket.Conn.Close. The ShutdownTimeout option bounds the wait for the echo.
package main
import (
"github.com/garyburd/websocket"
)
func main() {
var c *websocket.Conn // obtained from websocket.Dial or websocket.Upgrade
defer c.Close()
if err := c.Shutdown(websocket.CloseNormalClosure, "bye"); err != nil {
return // ... handle error ...
}
// Drain until the closing handshake completes (or the connection fails); the
// peer's echoed close surfaces here as the terminal read error.
for {
if _, _, err := c.ReadMessage(nil); err != nil {
break
}
}
}
Output:
func (*Conn) Subprotocol ¶
Subprotocol returns the negotiated subprotocol, or "" if none.
func (*Conn) Write ¶
func (c *Conn) Write(ctx context.Context, mt MessageType, opts *WriteOptions, fn func(*Writer) error) error
Write passes a streaming message writer to fn and finishes the message when fn returns.
ctx bounds only writer acquisition; opts bounds the body.
An fn error is returned unchanged, so applications can match their own errors with errors.Is or errors.As. ErrInvalidArgument and acquisition cancellation (errors.Is matches context.Canceled or context.DeadlineExceeded) leave the connection untouched; after any other error the connection is unusable. A writer timeout tears it down, and other fn errors start a graceful CloseInternalError handshake.
Outbound text is not validated; check untrusted text (e.g. utf8.Valid) before sending, or the peer may close with 1007. A panic in fn tears down the connection and propagates.
func (*Conn) WriteMessage ¶
func (c *Conn) WriteMessage(ctx context.Context, mt MessageType, opts *WriteOptions, data []byte) error
WriteMessage sends data as one message and one frame. ctx bounds only writer acquisition. Outbound text is not validated.
type DialOptions ¶
type DialOptions struct {
// Transport performs the HTTP upgrade. If nil, Dial uses an
// [http.Transport] with HTTP/2 disabled and [http.ProxyFromEnvironment].
//
// A custom transport must use HTTP/1.1 and return an [io.ReadWriteCloser]
// as the body of a 101 response. The standard [http.Transport] does so.
// Do not share a [tls.Config] (or the whole transport) with net/http: that
// puts "h2" in NextProtos, ALPN negotiates HTTP/2, and the handshake fails.
Transport http.RoundTripper
// Subprotocols lists Sec-WebSocket-Protocol values in preference order.
// Each value must be a nonempty HTTP token. See [Conn.Subprotocol].
Subprotocols []string
// ControlReplyTimeout bounds automatic pong and close writes. Zero waits
// indefinitely. It does not apply to keepalive pings, [Conn.Shutdown], or
// data messages.
ControlReplyTimeout time.Duration
// ShutdownTimeout bounds both sending a close and waiting for its response.
// Expiry tears down the connection with [ErrTimeout]. Zero waits indefinitely.
ShutdownTimeout time.Duration
// MaxMessageSize limits one inbound message. Exceeding it sends
// [CloseMessageTooBig] and returns [ErrProtocol]. Zero is unlimited.
MaxMessageSize int
// WriteBufferSize is the per-frame coalescing buffer size. Zero uses 4 KiB;
// values below 64 use 64.
WriteBufferSize int
// ResponseBodyLimit limits the captured body of a failed handshake. Zero
// discards it. A malformed 101 body is always discarded because it is the
// upgraded connection, not an HTTP error body.
ResponseBodyLimit int
// ManualCloseResponse disables the automatic response to a peer close.
// The application may finish pending writes, then call [Conn.Shutdown].
ManualCloseResponse bool
}
DialOptions configures Dial. Zero values disable optional behavior; WriteBufferSize defaults to 4 KiB.
Dial reads the options only during the call.
type MessageType ¶
type MessageType int
MessageType identifies a binary or text message. Its zero value is MessageBinary.
const ( MessageBinary MessageType = iota MessageText )
func (MessageType) String ¶
func (m MessageType) String() string
String returns the type name or its decimal value.
type ReadOptions ¶
type ReadOptions struct {
// IdleTimeout bounds the wait for the next data message. Control frames do
// not reset it. Zero waits indefinitely; expiry is terminal.
IdleTimeout time.Duration
// KeepaliveInterval sends a ping after this much inbound silence. Qualifying
// inbound frames reset the interval. Zero disables keepalive.
KeepaliveInterval time.Duration
// KeepaliveTimeout bounds sending a keepalive ping and receiving a qualifying
// response. Zero sends pings without requiring a response. It requires a
// nonzero KeepaliveInterval.
//
// Allow enough time for any in-flight message plus the round trip. The
// interval restarts when a check completes, so the gap between pings is
// KeepaliveInterval plus the check's duration; to survive an external idle
// limit (a proxy or load balancer), keep KeepaliveInterval +
// KeepaliveTimeout below that limit.
KeepaliveTimeout time.Duration
// MatchPong requires a pong matching this connection's ping. Otherwise any
// inbound control frame refreshes keepalive.
MatchPong bool
// MessageTimeout bounds a message body from message start. Zero is unbounded.
// It conflicts with MinReadRate; [Reader.SetReadDeadline] overrides it.
MessageTimeout time.Duration
// MinReadRate is the minimum body rate in bytes per second. A read receives
// size/rate time, so large buffers delay stall detection. Zero disables the
// rate check. It conflicts with MessageTimeout and [Reader.SetReadDeadline].
MinReadRate int
// SkipUTF8Validation disables validation of inbound text messages. Invalid
// text otherwise closes the connection with [CloseInvalidData].
SkipUTF8Validation bool
}
ReadOptions configures one Conn.Read or Conn.ReadMessage. Nil disables read-side liveness checks.
A read copies the options when it begins. Idle and keepalive settings apply before a message; message timeout, rate, and Reader.SetReadDeadline apply to its body.
Example (PerReadIdleTimeout) ¶
A server that expects the client to send a message immediately after connecting and then messages at any interval uses two *ReadOptions: a 10s IdleTimeout (a hard cap on receiving the first message), and for the steady state no cap. Keepalive instead detects a dead client. IdleTimeout is per-call precisely because the first read and the steady reads differ.
package main
import (
"time"
"github.com/garyburd/websocket"
)
func main() {
var c *websocket.Conn // obtained from websocket.Upgrade
first := &websocket.ReadOptions{IdleTimeout: 10 * time.Second}
steady := &websocket.ReadOptions{
KeepaliveInterval: 30 * time.Second,
KeepaliveTimeout: 10 * time.Second,
MatchPong: true,
}
if _, _, err := c.ReadMessage(first); err != nil {
return // client stayed silent within 10s
}
for {
_, _, err := c.ReadMessage(steady)
if err != nil {
return
}
// ... handle the message ...
}
}
Output:
type Reader ¶
type Reader struct {
// contains filtered or unexported fields
}
Reader streams one inbound message. It is valid only during its Conn.Read callback.
func (*Reader) Abort ¶
Abort stops reading without draining the current message and sends a best-effort close with code and reason.
An invalid code or invalid UTF-8 in reason returns ErrInvalidArgument without aborting. After a successful Abort, Conn.Read returns the callback error or ErrClosed.
func (*Reader) SetReadDeadline ¶
SetReadDeadline sets the absolute deadline for the current message body. A zero value removes the deadline. It overrides ReadOptions.MessageTimeout.
Expiry is terminal. SetReadDeadline conflicts with ReadOptions.MinReadRate.
func (*Reader) Type ¶
func (r *Reader) Type() MessageType
Type returns MessageBinary or MessageText.
type UpgradeOptions ¶
type UpgradeOptions struct {
// SelectSubprotocol selects a value offered in Sec-WebSocket-Protocol.
// Return "" for none. See [SupportedSubprotocols].
SelectSubprotocol func(*http.Request) string
// CheckOrigin approves the Origin header. If nil, Upgrade accepts an absent
// Origin or one whose host equals the request Host. See [AllowedOrigins].
// Browsers do not apply CORS to WebSocket upgrades, so a permissive check
// invites cross-site WebSocket hijacking.
CheckOrigin func(*http.Request) bool
// ResponseHeader adds headers to the 101 response. Upgrade overwrites its
// protocol-managed headers.
ResponseHeader http.Header
// OnError writes a rejected handshake response. err wraps
// [ErrBadHandshake]. The callback must not hijack or write a success status.
// If nil, Upgrade uses [http.Error].
OnError func(w http.ResponseWriter, r *http.Request, status int, err error)
// ControlReplyTimeout bounds automatic pong and close writes. Zero waits
// indefinitely. It does not apply to keepalive pings, [Conn.Shutdown], or
// data messages.
ControlReplyTimeout time.Duration
// ShutdownTimeout bounds both sending a close and waiting for its response.
// Expiry tears down the connection with [ErrTimeout]. Zero waits indefinitely.
ShutdownTimeout time.Duration
// MaxMessageSize limits one inbound message. Exceeding it sends
// [CloseMessageTooBig] and returns [ErrProtocol]. Zero is unlimited.
MaxMessageSize int
// WriteBufferSize is the per-frame coalescing buffer size. Zero uses 4 KiB;
// values below 64 use 64.
WriteBufferSize int
// ManualCloseResponse disables the automatic response to a peer close.
// The application may finish pending writes, then call [Conn.Shutdown].
ManualCloseResponse bool
}
UpgradeOptions configures Upgrade. Zero values disable optional behavior; WriteBufferSize defaults to 4 KiB.
Upgrade reads the options only during the call.
type WriteOptions ¶
type WriteOptions struct {
// MessageTimeout bounds a message from callback entry. Zero is unbounded.
// It conflicts with MinWriteRate; [Writer.SetWriteDeadline] overrides it.
MessageTimeout time.Duration
// MinWriteRate is the minimum body rate in bytes per second. A frame receives
// size/rate time, so large frames delay stall detection. Zero disables the
// rate check. It conflicts with MessageTimeout and [Writer.SetWriteDeadline].
MinWriteRate int
}
WriteOptions configures one Conn.Write or Conn.WriteMessage. Nil disables write-side liveness checks.
A write copies the options when it begins. Its context bounds only writer acquisition; these options bound the message body.
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer streams one outbound message and coalesces small writes. It is valid only during its Conn.Write callback.
func (*Writer) Final ¶
func (w *Writer) Final()
Final makes the next Writer.Write or Writer.WriteString finish the message. It is an optional optimization; Conn.Write otherwise finishes the message when the callback returns.
Example ¶
When a buffered writer is layered on the websocket.Writer, call websocket.Writer.Final just before flushing it. The flush then emits the message's last bytes as the final frame (FIN set), instead of the message ending with a separate empty terminating frame when the callback returns.
package main
import (
"bufio"
"context"
"github.com/garyburd/websocket"
)
func main() {
var c *websocket.Conn // obtained from websocket.Dial or websocket.Upgrade
err := c.Write(context.Background(), websocket.MessageText, nil, func(w *websocket.Writer) error {
bw := bufio.NewWriter(w)
// ... write the message to bw, e.g. with a json.Encoder ...
bw.WriteString("hello, world")
w.Final() // the next flush ends the message
return bw.Flush() // sends the buffered bytes as the final frame
})
if err != nil {
return // ... handle write error ...
}
}
Output:
func (*Writer) ReadFrom ¶
ReadFrom copies r into the message without finishing it.
A source error fails the message and causes Conn.Write to close gracefully.
func (*Writer) SetWriteDeadline ¶
SetWriteDeadline sets the absolute deadline for the current message body. A zero value removes the deadline. It overrides WriteOptions.MessageTimeout.
Expiry is terminal. SetWriteDeadline conflicts with WriteOptions.MinWriteRate.
func (*Writer) Write ¶
Write adds p to the message. After Writer.Final, it also finishes it.
func (*Writer) WriteString ¶
WriteString is the io.StringWriter form of Writer.Write.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
chat
command
Command chat is a multi-user chat server demonstrating the websocket package.
|
Command chat is a multi-user chat server demonstrating the websocket package. |
|
command
command
Command command runs a subprocess and bridges its standard input, output, and error streams to a websocket connection, demonstrating the websocket package and a MessageScanner read loop.
|
Command command runs a subprocess and bridges its standard input, output, and error streams to a websocket connection, demonstrating the websocket package and a MessageScanner read loop. |