Dwarves
Memo
Type ESC to close search bar

WebSockets

What are WebSockets

Previously, creating web applications that need bidirectional require a HTTP polling for updating the data from the server. This result in lots of problems such as high overhead, latency, not-truthly realtime.

WebSocket is a simple solution that is invented to solve those problems as it helps to maintain one single TCP connection for traffic in both directions. It currently can work over HTTP port 80, 443 and as proxies as it is designed for addressing the other existing bidirectional HTTP technologies so that take advantage of existing HTTP infrastructure.

The Protocol Overview

Handshake

A HTTP Handshake is preformed before update to WebSocket connection. The client makes a GET request to the server with an upgrade header. The server then response with status 101 to upgrade the current connection to be WebSocket connection. Otherwise, the client has to end the connection.

Example handshake

From client

GET /chat HTTP/1.1
    Host: server.example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Origin: http://example.com
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13

From server

HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
    Sec-WebSocket-Protocol: chat

Data Transfer

After the handshake was successful, each side can start sending or receiving data. The data property in WebSocket is message. For each message, the browser is only able to send and receive messages as binary or plain text.

WebSocket uses sequential frames for transferring message instead of streaming. This result in each side can exchange data independently without any blocking.

*Framing

A Frame is a small header + payload, the payload is similiar to other application data such as body of a HTTP message. In most basic form of WebSocket protocols include 2 type of frames:

Read detail here

*Authentication

The protocol itself does not specify an authentication method. User can use any other mechanism used in HTTP such as TLS authentication, cookies or authentication Header (Except for browser client, WebSocket api does not provide a way to modify the client handshake Header).

*WebSocket URI

ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ]
wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ]

Note that the differences between ws and wssis:

WebSocket Browser API

The browser provide an API for creating and managing WebSocket connection as well as exchange messages with a WebSocket server.

Open WebSocket connection

We can instantiate a new WebSocket connection, linking to the WebSocket server, and it will start connecting immediately.

const socket = new WebSocket("ws://localhost:8080")

WebSocket Events

In total, there are 4 events we can listen to are open, message, error, and close.

// Connection opened
socket.addEventListener("open", (event) => {});
// Receive messages from server
socket.addEventListener("message", (event) => {});
// Connection Error
socket.addEventListener("error", (event) => {})
// After connection closed
socket.addEventListener("close", (event) => {})

Sending message The socket.send(body) method allow sending a message to the server. The body argument can be a string or binary format type such as ArrayBuffer, Blob.

Receiving message

Access event.data for incomming message

socket.onmessage = (event) => {
  console.log(event.data)
}
socket.binaryType = "arraybuffer"
socket.onmessage = (event) => {
  if (event.data instanceof ArrayBuffer) {
    // Handling binary message
    return
  }
  // Handling String message
}

Rate Limiting

When user has a slow network connection. After calling WebSocket.send(...) the data will be buffered in memory and will be sent out as soon as connection get better

WebSocket.bufferedArmount return the amount of data queued using call() but not yet send out to the network. This value will not reset to zero if connection close.

if (socket.bufferedAmount === 0) {
  socket.send(moreData())
}

Close Connection

For sending close frame from browser WebSocket, simply call WebSocket.close(code, reason).

socket.close(1000, "Complete") // both argument is optional
socket.onclose = (event) => {
  const { code, reason, wasClean } = event
  console.log({code, reason, wasClean})
  // { code: 1000, reason: "Complete", wasClean: true }
}

*Common code

Connection State

User can access WebSocket.readyState for getting the current state of a WebSocket instance