The Conn type represents a WebSocket connection and provides methods for reading and writing messages, managing connection lifecycle, and configuring connection behavior.
type Conn struct {
// unexported fields
}The Conn type has no exported fields. All interaction is through methods.
Helper method for reading a complete message into a byte slice.
func (c *Conn) ReadMessage() (messageType int, p []byte, err error)Returns the message type (TextMessage or BinaryMessage) and the message payload. This is a convenience method that internally uses NextReader.
Example:
for {
messageType, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
break
}
log.Printf("Received %d: %s", messageType, message)
}Returns the next data message received from the peer as an io.Reader.
func (c *Conn) NextReader() (messageType int, r io.Reader, err error)The returned messageType is either TextMessage or BinaryMessage. There can be at most one open reader on a connection. NextReader discards the previous message if the application has not already consumed it.
Applications must break out of the read loop when this method returns a non-nil error value. Errors returned from this method are permanent. Once this method returns a non-nil error, all subsequent calls return the same error.
Example:
for {
messageType, reader, err := conn.NextReader()
if err != nil {
log.Println("NextReader error:", err)
break
}
// Read message using io.Reader interface
message, err := io.ReadAll(reader)
if err != nil {
log.Println("Read error:", err)
break
}
log.Printf("Received %d: %s", messageType, message)
}Reads the next JSON-encoded message from the connection and stores it in the value pointed to by v.
func (c *Conn) ReadJSON(v interface{}) errorUses the encoding/json package for unmarshaling.
Example:
type Message struct {
Type string `json:"type"`
Data string `json:"data"`
}
var msg Message
err := conn.ReadJSON(&msg)
if err != nil {
log.Println("ReadJSON error:", err)
return
}
log.Printf("Received: %+v", msg)Helper method for writing a complete message from a byte slice.
func (c *Conn) WriteMessage(messageType int, data []byte) errorThis is a convenience method that internally uses NextWriter. The messageType can be TextMessage, BinaryMessage, or any control message type (CloseMessage, PingMessage, PongMessage).
Example:
err := conn.WriteMessage(websocket.TextMessage, []byte("Hello"))
if err != nil {
log.Println("Write error:", err)
return
}Returns a writer for the next message to send.
func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error)The writer's Close method flushes the complete message to the network. There can be at most one open writer on a connection. NextWriter closes the previous writer if the application has not already done so.
All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage, PongMessage) are supported.
Example:
writer, err := conn.NextWriter(websocket.TextMessage)
if err != nil {
log.Println("NextWriter error:", err)
return
}
_, err = writer.Write([]byte("Hello "))
if err != nil {
log.Println("Write error:", err)
return
}
_, err = writer.Write([]byte("World"))
if err != nil {
log.Println("Write error:", err)
return
}
err = writer.Close()
if err != nil {
log.Println("Close error:", err)
return
}Writes the JSON encoding of v as a message.
func (c *Conn) WriteJSON(v interface{}) errorUses the encoding/json package for marshaling.
Example:
type Message struct {
Type string `json:"type"`
Data string `json:"data"`
}
msg := Message{Type: "greeting", Data: "Hello"}
err := conn.WriteJSON(msg)
if err != nil {
log.Println("WriteJSON error:", err)
return
}Writes a control message with the given deadline.
func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) errorThe allowed message types are CloseMessage, PingMessage, and PongMessage. This method can be called concurrently with other write methods.
Example sending a ping:
deadline := time.Now().Add(10 * time.Second)
err := conn.WriteControl(websocket.PingMessage, []byte(""), deadline)
if err != nil {
log.Println("Ping error:", err)
}Writes a prepared message into the connection.
func (c *Conn) WritePreparedMessage(pm *PreparedMessage) errorSee the PreparedMessage section below for details on creating prepared messages.
Caches wire representations of a message payload for efficient sending to multiple connections.
type PreparedMessage struct {
// unexported fields
}PreparedMessage is especially useful when compression is used because the CPU and memory expensive compression operation can be executed once for a given set of compression options.
Returns an initialized PreparedMessage.
func NewPreparedMessage(messageType int, data []byte) (*PreparedMessage, error)Valid wire representation will be calculated lazily only once for a set of current connection options.
Example:
// Prepare a message once
pm, err := websocket.NewPreparedMessage(websocket.TextMessage, []byte("broadcast"))
if err != nil {
log.Fatal(err)
}
// Send to multiple connections efficiently
for _, conn := range connections {
err := conn.WritePreparedMessage(pm)
if err != nil {
log.Printf("Write error: %v", err)
}
}Closes the underlying network connection without sending or waiting for a close message.
func (c *Conn) Close() errorFor a graceful close, send a close message before calling Close:
err := conn.WriteMessage(websocket.CloseMessage,
websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Println("Write close error:", err)
}
conn.Close()Sets the read deadline on the underlying network connection.
func (c *Conn) SetReadDeadline(t time.Time) errorAfter a read has timed out, the websocket connection state is corrupt and all future reads will return an error. A zero value for t means reads will not time out.
Example:
// Set 30 second read timeout
conn.SetReadDeadline(time.Now().Add(30 * time.Second))
messageType, message, err := conn.ReadMessage()
if err != nil {
if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
log.Println("Read timeout")
} else {
log.Println("Read error:", err)
}
return
}Sets the write deadline on the underlying network connection.
func (c *Conn) SetWriteDeadline(t time.Time) errorAfter a write has timed out, the websocket state is corrupt and all future writes will return an error. A zero value for t means writes will not time out.
Example:
// Set 10 second write timeout
conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
err := conn.WriteMessage(websocket.TextMessage, []byte("Hello"))
if err != nil {
log.Println("Write error:", err)
}Sets the maximum size in bytes for a message read from the peer.
func (c *Conn) SetReadLimit(limit int64)If a message exceeds the limit, the connection sends a close message to the peer and returns ErrReadLimit to the application.
Example:
// Limit messages to 1MB
conn.SetReadLimit(1024 * 1024)
_, message, err := conn.ReadMessage()
if err == websocket.ErrReadLimit {
log.Println("Message too large")
return
}Returns the local network address.
func (c *Conn) LocalAddr() net.AddrExample:
addr := conn.LocalAddr()
log.Printf("Local address: %s", addr.String())Returns the remote network address.
func (c *Conn) RemoteAddr() net.AddrExample:
addr := conn.RemoteAddr()
log.Printf("Remote address: %s", addr.String())Returns the negotiated protocol for the connection.
func (c *Conn) Subprotocol() stringExample:
protocol := conn.Subprotocol()
if protocol != "" {
log.Printf("Using subprotocol: %s", protocol)
}Returns the underlying connection that is wrapped by the Conn.
func (c *Conn) NetConn() net.ConnWarning: Writing to or reading from this connection directly will corrupt the WebSocket connection.
Example (for inspection only):
netConn := conn.NetConn()
log.Printf("Underlying connection type: %T", netConn)func (c *Conn) UnderlyingConn() net.ConnDeprecated: Use NetConn instead.
func echoHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println(err)
return
}
defer conn.Close()
for {
messageType, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
break
}
err = conn.WriteMessage(messageType, message)
if err != nil {
log.Println("Write error:", err)
break
}
}
}func streamHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
defer conn.Close()
for {
messageType, reader, err := conn.NextReader()
if err != nil {
break
}
writer, err := conn.NextWriter(messageType)
if err != nil {
break
}
if _, err := io.Copy(writer, reader); err != nil {
break
}
if err := writer.Close(); err != nil {
break
}
}
}type Request struct {
Action string `json:"action"`
Data string `json:"data"`
}
type Response struct {
Status string `json:"status"`
Result string `json:"result"`
}
func jsonHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
defer conn.Close()
for {
var req Request
err := conn.ReadJSON(&req)
if err != nil {
log.Println("ReadJSON error:", err)
break
}
// Process request
resp := Response{
Status: "ok",
Result: "Processed: " + req.Data,
}
err = conn.WriteJSON(resp)
if err != nil {
log.Println("WriteJSON error:", err)
break
}
}
}type Hub struct {
connections map[*websocket.Conn]bool
broadcast chan []byte
}
func (h *Hub) run() {
for {
message := <-h.broadcast
// Prepare message once
pm, err := websocket.NewPreparedMessage(websocket.TextMessage, message)
if err != nil {
log.Println("Prepare error:", err)
continue
}
// Send to all connections
for conn := range h.connections {
err := conn.WritePreparedMessage(pm)
if err != nil {
log.Println("Write error:", err)
conn.Close()
delete(h.connections, conn)
}
}
}
}func readLoop(conn *websocket.Conn) {
// Set read deadline before each read
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
// Set pong handler to reset deadline
conn.SetPongHandler(func(string) error {
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
return nil
})
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
break
}
// Reset deadline after successful read
conn.SetReadDeadline(time.Now().Add(60 * time.Second))
// Process message
log.Printf("Received: %s", message)
}
}Connections support one concurrent reader and one concurrent writer. Applications are responsible for ensuring:
The Close and WriteControl methods can be called concurrently with all other methods.
func handleConnection(conn *websocket.Conn) {
defer conn.Close()
// Start reader goroutine
go func() {
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("Read error:", err)
return
}
log.Printf("Received: %s", message)
}
}()
// Writer in main goroutine
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for {
select {
case <-ticker.C:
err := conn.WriteMessage(websocket.TextMessage, []byte("ping"))
if err != nil {
log.Println("Write error:", err)
return
}
}
}
}var ErrCloseSent = errors.New("websocket: close sent")Returned when the application writes a message to the connection after sending a close message.
var ErrReadLimit = errors.New("websocket: read limit exceeded")Returned when reading a message that is larger than the read limit set for the connection.
func ReadJSON(c *Conn, v interface{}) errorDeprecated: Use c.ReadJSON instead.
func WriteJSON(c *Conn, v interface{}) errorDeprecated: Use c.WriteJSON instead.
func JoinMessages(c *Conn, term string) io.ReaderConcatenates received messages to create a single io.Reader. The string term is appended to each message. The returned reader does not support concurrent calls to the Read method.
Example:
reader := websocket.JoinMessages(conn, "\n")
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
line := scanner.Text()
log.Printf("Line: %s", line)
}