⚠️ Maintenance. Notice: the site is currently in maintenance mode, so the amount of available material is temporarily limited.
Home / Tutorials / WebSocket basicsОсновы WebSocket

WebSocket basics: your first connectionОсновы WebSocket: первое соединение

Why WebSocket existsЗачем нужен WebSocket

Classic HTTP is request/response: the client asks, the server answers, the connection is done. To get fresh data you either poll on a timer (wasteful and laggy) or hold a request open with long-polling (awkward). The WebSocket protocol, standardised as RFC 6455, solves this by upgrading a single HTTP connection into a persistent, full-duplex channel. After the upgrade, either side can send a message at any time with almost no per-message overhead.

That makes it the natural transport for chat, multiplayer games, collaborative editors, trading screens, live dashboards and notifications.

Классический HTTP — это запрос/ответ: клиент спрашивает, сервер отвечает, соединение закрывается. Чтобы получать свежие данные, вы либо опрашиваете сервер по таймеру (расточительно и с задержкой), либо удерживаете запрос открытым через long-polling (неуклюже). Протокол WebSocket, стандартизированный в RFC 6455, решает это, превращая одно HTTP-соединение в постоянный полнодуплексный канал. После апгрейда любая сторона может отправить сообщение в любой момент почти без накладных расходов на каждое сообщение.

Поэтому это естественный транспорт для чатов, мультиплеерных игр, совместных редакторов, биржевых терминалов, живых дашбордов и уведомлений.

The upgrade handshakeРукопожатие (upgrade)

A WebSocket connection starts life as an ordinary HTTP GET carrying an Upgrade header. If the server agrees, it replies with 101 Switching Protocols and the same TCP socket is now a WebSocket.

handshake (request)
GET /v1 HTTP/1.1
Host: echo.socketforge.dev
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

The server hashes the key with a fixed GUID and echoes it back in Sec-WebSocket-Accept, proving it understood the protocol:

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

You almost never write this by hand — the browser and server libraries do it. But it explains why a WebSocket lives on http:///https:// ports and passes through the same proxies as normal web traffic.

WebSocket-соединение начинается как обычный HTTP GET с заголовком Upgrade. Если сервер согласен, он отвечает 101 Switching Protocols, и тот же TCP-сокет становится WebSocket-ом.

рукопожатие (запрос)
GET /v1 HTTP/1.1
Host: echo.socketforge.dev
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

Сервер хеширует ключ с фиксированным GUID и возвращает результат в Sec-WebSocket-Accept, подтверждая, что понял протокол:

рукопожатие (ответ)
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

Вручную это писать почти никогда не нужно — браузер и серверные библиотеки делают всё сами. Но это объясняет, почему WebSocket живёт на портах http:///https:// и проходит через те же прокси, что и обычный веб-трафик.

The four ready statesЧетыре состояния соединения

Every WebSocket instance exposes a numeric readyState. Knowing it is the difference between a clean app and a pile of “socket is not open” errors.

  • 0 — CONNECTING: handshake in flight, you may not send yet.
  • 1 — OPEN: ready; send() works.
  • 2 — CLOSING: a close handshake started.
  • 3 — CLOSED: done, or never opened.

Каждый экземпляр WebSocket предоставляет числовой readyState. Понимание этого — разница между аккуратным приложением и кучей ошибок «socket is not open».

  • 0 — CONNECTING: рукопожатие в процессе, отправлять ещё нельзя.
  • 1 — OPEN: готово; send() работает.
  • 2 — CLOSING: начато закрывающее рукопожатие.
  • 3 — CLOSED: завершено или так и не открылось.

A minimal browser clientМинимальный браузерный клиент

The client API is just four events and two methods. Note that we only call send() after onopen fires:

client.js
const ws = new WebSocket("wss://echo.socketforge.dev/v1");

ws.addEventListener("open", () => {
  console.log("open, readyState =", ws.readyState);
  ws.send(JSON.stringify({ type: "hello", t: Date.now() }));
});

ws.addEventListener("message", (e) => {
  const msg = JSON.parse(e.data);
  console.log("received", msg);
});

ws.addEventListener("close", (e) =>
  console.log("closed", e.code, e.reason));

ws.addEventListener("error", () =>
  console.warn("socket error — close will follow"));
Always prefer wss:// (TLS) over ws://. Browsers block insecure WebSockets from HTTPS pages, and plaintext frames are trivially readable on the network.

Клиентский API — это всего четыре события и два метода. Обратите внимание: send() вызываем только после срабатывания onopen:

client.js
const ws = new WebSocket("wss://echo.socketforge.dev/v1");

ws.addEventListener("open", () => {
  console.log("open, readyState =", ws.readyState);
  ws.send(JSON.stringify({ type: "hello", t: Date.now() }));
});

ws.addEventListener("message", (e) => {
  const msg = JSON.parse(e.data);
  console.log("received", msg);
});

ws.addEventListener("close", (e) =>
  console.log("closed", e.code, e.reason));

ws.addEventListener("error", () =>
  console.warn("socket error — close will follow"));
Всегда предпочитайте wss:// (TLS) вместо ws://. Браузеры блокируют небезопасные WebSocket-ы со страниц HTTPS, а кадры открытым текстом легко читаются в сети.

A minimal Node.js echo serverМинимальный echo-сервер на Node.js

Using the popular ws package, a server that echoes every message back is just a few lines:

server.js
// npm i ws  —  node server.js
import { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (socket, req) => {
  console.log("client connected from", req.socket.remoteAddress);

  socket.on("message", (data, isBinary) => {
    // Echo back exactly what we got
    socket.send(data, { binary: isBinary });
  });

  socket.on("close", () => console.log("client gone"));
});

Run it, point the client at ws://localhost:8080, and you have a working round-trip. In production you would terminate TLS at a reverse proxy (Caddy, nginx) and forward the upgrade to this process.

С популярным пакетом ws сервер, отражающий каждое сообщение обратно, занимает несколько строк:

server.js
// npm i ws  —  node server.js
import { WebSocketServer } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (socket, req) => {
  console.log("client connected from", req.socket.remoteAddress);

  socket.on("message", (data, isBinary) => {
    // Возвращаем ровно то, что получили
    socket.send(data, { binary: isBinary });
  });

  socket.on("close", () => console.log("client gone"));
});

Запустите его, направьте клиент на ws://localhost:8080 — и у вас есть рабочий round-trip. В продакшене TLS терминируется на обратном прокси (Caddy, nginx), который пробрасывает upgrade в этот процесс.

Where to go nextЧто дальше

You can send and receive — now make it robust. Real networks drop sockets, so read Reconnection with exponential backoff, then add a heartbeat so you notice dead connections quickly.

Вы умеете отправлять и принимать — теперь сделайте это надёжным. Реальные сети рвут сокеты, поэтому прочитайте «Переподключение с экспоненциальной задержкой», а затем добавьте heartbeat, чтобы быстро замечать мёртвые соединения.