bhylu.com

Advertisements

Node.js WebSocket

A WebSocket connection supports messages in both directions after its handshake. Decide message size, schema, authentication and connection lifetime rather than treating every received string as an application command.

How it works

The reviewed ws 8.18.3 package supplies the server and client for this isolated local fixture. maxPayload limits the server’s accepted message size, and the application only answers the exact known ping message. A production service needs origin and credential policy, heartbeat/disconnect handling and rate limits. Those are not supplied automatically by a successful echo-style demonstration.

Run the code

Run this example locally with Node.js. The exact sources are reviewed on Node 22.15.1 and Node 24.22.1 unless a specialised lab states otherwise. Save the complete source as websocket.mjs in a separate empty exercises folder and run node websocket.mjs. There is no Node.js browser runner on Bhylu; the plain JavaScript playground does not provide these filesystem, server or process APIs. In that separate project, install the reviewed packages with npm install --save-exact ws@8.18.3. These are teaching dependencies, not changes to the Bhylu website package tree.

Download the complete source. Ordinary Node scripts need no Apache, PHP or MySQL service. File examples own their temporary folders; network fixtures use loopback and available temporary ports.

Example

websocket.mjs

import { WebSocketServer, WebSocket } from 'ws';
import { once } from 'node:events';
const server = new WebSocketServer({ host: '127.0.0.1', port: 0, maxPayload: 1024 });
server.on('connection', (socket) =>
  socket.on('message', (data) => {
    if (data.toString() === 'desk:ping') socket.send('desk:ready');
  }),
);
await once(server, 'listening');
const client = new WebSocket('ws://127.0.0.1:' + server.address().port);
try {
  await once(client, 'open');
  const answer = once(client, 'message');
  client.send('desk:ping');
  const [message] = await answer;
  console.log(message.toString());
} finally {
  client.terminate();
  for (const socket of server.clients) socket.terminate();
  await new Promise((resolve) => server.close(resolve));
}

Expected result

desk:ready

The message crosses an actual loopback WebSocket connection and only the fixed command receives the expected answer. This is not a durable queue or evidence that messages survive disconnects. The fixture explicitly terminates its owned connections.

Use the Node.js API reference for the precise version contract.