WebSocket API

I want to read about the WebSocket API because I need to either use web sockets or server sent events to implement push notifications.

Date Created:
1 47

References



Related


  • Backpressure
    • An important concept in streams is backpressure - this is the process by which a single stream or pipe chain regulates the speed of reading/writing. When a stream later in the chain is still busy and isn't yet ready to accept more chunks, it sends a signal backwards through the chain to tell earlier transform streams (or the original source) to slow down delivery so that you don't end up with a bottleneck anywhere.
  • WebSocket Opening Handshake
    • The server must listen for incoming socket connections using a standard TCP socket. Depending on your platform, this may be handled for you automatically. The handshake is the Web in WebSockets. It's the bridge from HTTP to WebSockets. In the handshake, details of the connection are negotiated, and either party can back out before completion if the terms are unfavorable. The server must be careful to understand everything the client asks for, otherwise security issues can occur.
  • Berkeley Sockets
    • A Berkeley socket is an Application programming interface (API) for Internet domain sockets and Unix domain sockets, used for inter-process communication. It is commonly implemented as a library of linkable modules. It originated with the 4.2BSD Unix operating system, which was released in 1983.
    • A socket is an abstract representation (handle) for the local endpoint of a network communication path. The Berkeley sockets API represents it as a file descriptor in the Unix philosophy that provides a common interface for input and output streams of data.


Notes


The WebSocket API makes it possible to open a two-way interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive responses without having to poll the server for a reply.

The WebSocket API provides two alternative mechanisms for creating and using web socket connections: the WebSocket interface and the WebSocketStream interface.

  • The WebSocket interface is stable and has good browser and server support. However, it doesn't support backpressure. As a result, when messages arrive faster than the application can process them it will either fill up the device's memory by buffering those messages, become unresponsive due to 100% CPU usage, or both.
  • The WebSocketStream interface is a Promise-based alternative to WebSocket. It uses the Streams API to handle receiving and sending messages, meaning that socket connections can take advantage of stream backpressure automatically, regulating the speed of reading and writing to avoid bottlenecks in the application. However, WebSocketStream is non-standard and currently only supported in one rendering engine.

The WebTransport API is similar to the WebSocket API, but is more low-level, versatile, and has less cross-browser support.

Interfaces

  • WebSocket
    • The primary interface for connecting to a WebSocket sever and then sending and receiving data on the connection.
  • WebSocketStream
    • Promise-based interface for connecting to a WebSocket server; uses streams to send and receive data on the connection.
  • CloseEvent
    • The event sent by the WebSocket object when the connection closes.
  • MessageEvent
    • The event sent y the WebSocket object when a message is received from the server.

Related HTTP Headers

  • Sec-WebSocket-Key
    • An HTTP request header that contains a nonce from the client. This is used in the WebSocket opening handshake to verify that the client explicitly intends to open a WebSocket. It is added automatically by the browser.
  • Sec-WebSocket-Accept
    • An HTTP response header used in the WebSocket opening handshake to indicate that the server is willing to upgrade to a WebSocket connection. The value in the directive is calculated from the value of Sec-WebSocket-Key in the corresponding request.
  • Sec-WebSocket-Version
    • An HTTP header that in requests indicates the version of the WebSocket protocol understood by the client. In responses, it is sent only if the requested protocol version is not supported by the server, and lists the versions that the server supports.
  • Sec-WebSocket-Protocol
    • An HTTP header that in requests indicates the sub-protocols supported by the client in preferred order. In responses, it indicates the sub-protocol selected by the server from the client's preferences.
  • Sec-WebSocket-Extensions
    • An HTTP header that in requests indicates the WebSocket extensions supported by the client in preferred order. IN responses, it indicates the extension selected by the server from the client's preferences.

Tools


Writing WebSocket Client Applications


WebSocket client applications use the WebSocket API to communicate with WebSocket servers using the WebSocket protocol.

In order to communicate using the WebSocket protocol, you need to create a WebSocket object; this will automatically attempt to open the connection to the server. The WebSocket constructor accepts one required and one optional parameter.

webSocket = new WebSocket(url, protocols);
  • url
    • The URL to which to connect; this should be the URL to which the WebSocket server will respond. This should be the URL scheme wss://, although some software may allow you to use the insecure ws:// for a local connection. Relative URL values and https:// and http:// schemes are also allowed in most recent browser versions.
  • protocols
    • Either a single protocol string or an array of protocol strings. These strings are used to indicate sub-protocols, so that a single server can implement multiple WebSocket sub-protocols.

Connection Errors

If an error occurs while attempting to connect, an error event is first sent to the WebSocket object (thereby invoking any handlers), followed by a close event that indicates the reason for the connection's closing.

The browser may also output to its console a more descriptive error message as well as a closing code.

Example

// Creates a new WebSocket, connecting to the server in the 
// first argument. A custom protocol is named in this example
// On return, exampleSocket.readyState is CONNECTING. The
// readyState will become OPEN once the connection is ready
// to transfer data
const exampleSocket = new WebSocket(
"wss://www.example.com/socketserver",
"protocolOne",
);
// Soecify multiple protocols
// exampleSocket.protocol will tell you which protocol of the server is
// selected
const exampleSocket = new WebSocket("wss://www.example.com/socketserver", [
"protocolOne",
"protocolTwo",
]);

Sending Data to the Server

Once you've opened you connection, you can begin transmitting data to the server. To do this, call the WebSocket object's send() method for each message you want to send:

exampleSocket.send("Here's some text that the server is urgently awaiting!");

You can send data as a string, Blob or ArrayBuffer

You can make sure that sending data only takes place once a connection is established by defining an onopenevent handler to do the work:

exampleSocket.onopen = (event) => {
exampleSocket.send("Here's some text that the server is urgently awaiting!");
};

Using JSON to Transmit Objects

One handy thing you can do is use JSON to send reasonably complex data to the server.

Sending JSON Objects

// Send text to all users through the server
function sendText() {
// Construct a msg object containing the data the server needs to process the message from the chat client.
const msg = {
type: "message",
text: document.getElementById("text").value,
id: clientID,
date: Date.now(),
};

// Send the msg object as a JSON-formatted string.
exampleSocket.send(JSON.stringify(msg));

// Blank the text input element, ready to receive the next line of text from the user.
document.getElementById("text").value = "";
}

Receiving JSON Objects

exampleSocket.onmessage = (event) => {
const f = document.getElementById("chat-box").contentDocument;
let text = "";
const msg = JSON.parse(event.data);
const time = new Date(msg.date);
const timeStr = time.toLocaleTimeString();

switch (msg.type) {
case "id":
clientID = msg.id;
setUsername();
break;
case "username":
text = `User <em>${msg.name}</em> signed in at ${timeStr}<br>`;
break;
case "message":
text = `(${timeStr}) ${msg.name} : ${msg.text} <br>`;
break;
case "reject-username":
text = `Your username has been set to <em>${msg.name}</em> because the name you chose is in use.<br>`;
break;
case "user-list":
document.getElementById("user-list-box").innerText = msg.users.join("\n");
break;
}

if (text.length) {
f.write(text);
document.getElementById("chat-box").contentWindow.scrollByPages(1);
}
};

Text received over a WebSocket connection is in UTF-8 format.

Closing The Connection

When you've finished using the WebSocket connection, call the WebSocket method close().

exampleSocket.close();
It may be helpful to examine the socket's bufferedAmount attribute before attempting to close the connection to determine if any data has yet to be transmitted on the network. If this value isn't 0, there's pending data still, so you may wish to wait before closing the connection.

Writing WebSocket Servers


A WebSocket server is nothing more than an application listening on any port of a TCP server that follows a specific protocol. [...] It can actually be quite straightforward to implement a basic WebSocket server on your platform of choice

A WebSocket can be written in any server-side programming language that is capable of Berkeley sockets.

WebSocket servers are often separate and specialized servers (for load-balancing or other practical reasons), so you will often use a reverse proxy (such as a regular HTTP server) to detect WebSocket handshakes, pre-process them, and send those clients to a real WebSocket server.

The WebSocket handshake

First, the server must listen for incoming socket connections using a standard TCP socket. Depending on your platform, this may be handled for you automatically. For example, let's assume that your server is listening on example.com, port 8000, and your socket server responds to GET requests at example.com/chat.

The handshake is the bridge from HTTP to WebSockets. In the handshake, details of the connection are negotiated, and either party can back out before completion if the terms are unfavorable. The server must be careful to understand everything the client asks for, otherwise security issues can occur.

The client still has to start the WebSocket handshake process by contacting the server and requesting a WebSocket connection. The client will send a pretty standard HTTP request with headers that look like this:

GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

The client can solicit extensions and/or subprotocls here. Some other headers may be here. If any header is not understood or has an incorrect value, the server should send a 400 response and immediately close the socket. When the server receives the handshake request, it should send back a special response that indicates that the protocol will be changing from HTTP to WebSocket.

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

Once the server sends the Sec-WebSocket-Accept header, the handshake is complete and you can start swapping data.

Your server must keep track of clients' sockets so you don't keep handshaking again with clients who have already completed the handshake.

Exchanging Data Frames

Either the client or the server can choose to send a message at any time - that's the magic of WebSockets. However, extracting information from these so-called frames of data can be complicated.

Frame format:

0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+


pings and Pongs: The Heartbeat of WebSockets

At any point after the handshake, either the client or the server can choose to send a ping to the other party. When the ping is received, the recipient must send back a pong as soon as possible. You can use this to make sure that the client is still connected, for example.

Closing the Connection

To close a connection, either the client or server can send a control frame with data containing a specified control sequence to begin the closing handshake.

Miscellaneous

WebSocket extensions and subprotocols are negotiated via headers during the handshake. Sometimes extensions and subprotocols are very similar, but there is a clear distinction. Extensions control the WebSocket frame and modify the payload, while subprotocols structure the WebSocket payload and never modify anything. Think of an extension as compressing a file before emailing it to someone. Think of a subprotocol as a custom XML schema or a doctype declaration. You're still using XML and its syntax, but you're additionally restricted by a structure you agreed on. WebSocket subprotocols are just like that. They do not introduce anything fancy, they just establish structure.


Using WebSocketStream to Write in a Client


The WebSocketStream API is a Promise-based alternative to WebSocket for creating and using client-side WebSocket connections. WebSocketStream uses the Streams API to handle receiving and sending messages, meaning that socket connections can take advantage of stream backpressure automatically, regulating the speed of reading or writing to avoid bottlenecks in the application.

if ("WebSocketStream" in self) {
// WebSocketStream is supported
}
// Create a new WebSocketStream
const wss = new WebSocketStream("wss://example.com/wss");

Comments

You have to be logged in to add a comment

User Comments

Insert Math Markup

ESC
About Inserting Math Content
Display Style:

Embed News Content

ESC
About Embedding News Content

Embed Youtube Video

ESC
Embedding Youtube Videos

Embed TikTok Video

ESC
Embedding TikTok Videos

Embed X Post

ESC
Embedding X Posts

Embed Instagram Post

ESC
Embedding Instagram Posts

Insert Details Element

ESC

Example Output:

Summary Title
You will be able to insert content here after confirming the title of the <details> element.

Insert Table

ESC
Customization
Align:
Preview:

Insert Horizontal Rule

#000000

Preview:


View Content At Different Sizes

ESC

Edit Style of Block Nodes

ESC

Edit the background color, default text color, margin, padding, and border of block nodes. Editable block nodes include paragraphs, headers, and lists.

#ffffff
#000000

Edit Selected Cells

Change the background color, vertical align, and borders of the cells in the current selection.

#ffffff
Vertical Align:
Border
#000000
Border Style:

Edit Table

ESC
Customization:
Align:

Upload Lexical State

ESC

Upload a .lexical file. If the file type matches the type of the current editor, then a preview will be shown below the file input.

Upload 3D Object

ESC

Upload Jupyter Notebook

ESC

Upload a Jupyter notebook and embed the resulting HTML in the text editor.

Insert Custom HTML

ESC

Edit Image Background Color

ESC
#ffffff

Insert Columns Layout

ESC
Column Type:

Select Code Language

ESC
Select Coding Language

Insert Chart

ESC

Use the search box below

Upload Previous Version of Article State

ESC