Как поднять свой WebSocket сервер на Node.js: основы

от автора

Привет, Хабр!

Сегодня создадим свой WebSocket сервер на Node.js. Это тот самый протокол, который позволяет отправлять и принимать данные в реальном времени без перекладывания на HTTP. Для этого мы будем использовать библиотеку ws.

Подготовка окружения

Первый шаг — установить Node.js, если его еще нет. Ну а если есть, проверим версии:

node -v npm -v

Все на месте? Отлично. Теперь создадим папку для проекта:

mkdir websocket-server cd websocket-server npm init -y

Тут сразу заложим фундамент проекта. npm init -y создает стандартный package.json. Но не забудь туда добавить "type": "module", чтобы сразу подключать все по человески, без всяких require:

{   "type": "module",   "dependencies": {     "ws": "^8.12.0"   } }

Теперь пришло время установить библиотеку для работы с WebSocket — ws:

npm install ws

Это некий золотой стандарт среди библиотек для WebSocket на Node.js.

Создание базового WebSocket сервера

Окей, есть инструменты, пора за работу! В файле server.js создадим сервер WebSocket, который уже готов принять соединение. Минимум кода:

import { WebSocketServer } from 'ws';  const wss = new WebSocketServer({ port: 8080 });  wss.on('connection', (ws) => {   console.log('Новый клиент подключился!');    ws.on('message', (message) => {     console.log(`Получено сообщение: ${message}`);     ws.send('Сообщение получено!');   });    ws.on('close', () => {     console.log('Клиент отключился');   }); });

Разберем. Мы создали сервер на порту 8080. Как только клиент подключается, мы сообщаем об этом в консоль. Когда он присылает сообщение, сервер отвечает: «Сообщение получено!«. А когда клиент отключается, сервер говорит об этом. Запустим его:

node server.js

Теперь можно подключиться к серверу через браузер, Postman или вообще любой клиент WebSocket.

Обработка сообщений и работа с несколькими клиентами

Теперь научим сервер работать с несколькими клиентами одновременно и обрабатывать не только текст, но и бинарные данные.

Обработка бинарных данных

Чтобы обрабатывать бинарные данные, нужно убедиться, что сервер может различать текст и двоичные сообщения:

ws.on('message', (data, isBinary) => {   if (isBinary) {     console.log('Получены бинарные данные');   } else {     console.log(`Получено сообщение: ${data}`);   }   ws.send(data); // Отправляем обратно клиенту то, что получили });

Теперь сервер умеет отличать текстовые сообщения от бинарных и логирует их соответственно.

Множество клиентов

Но сервер не всегда работает с одним клиентом. Добавим возможность для нескольких клиентов обмениваться сообщениями. Будем сохранять всех подключенных клиентов в массиве и рассылаем сообщения всем остальным:

const clients = [];  wss.on('connection', (ws) => {   clients.push(ws);      ws.on('message', (message) => {     clients.forEach((client) => {       if (client !== ws && client.readyState === WebSocket.OPEN) {         client.send(message);       }     });   });    ws.on('close', () => {     clients.splice(clients.indexOf(ws), 1); // Убираем клиента из списка при отключении   }); });

Теперь, когда один клиент отправляет сообщение, оно транслируется всем остальным подключенным клиентам, кроме самого отправителя.

Безопасность

Нельзя говорить о серверной архитектуре, не затронув безопасность. WebSocket не исключение. Самый простой способ защиты — ограничить число подключений с одного IP-адреса и установить таймауты.

Ограничение числа подключений

Если хочешь избежать атак типа DoS, придется ограничить количество соединений с одного IP. Пример, как это сделать:

const ipConnections = new Map();  wss.on('connection', (ws, req) => {   const ip = req.socket.remoteAddress;      if (ipConnections.get(ip) >= 5) {     ws.close();     return;   }      ipConnections.set(ip, (ipConnections.get(ip) || 0) + 1);    ws.on('close', () => {     ipConnections.set(ip, ipConnections.get(ip) - 1);   }); });

Теперь сервер будет автоматически разрывать соединение, если с одного IP слишком много подключений.

Зашифрованные соединения

Да, да — WebSocket через SSL. Важно, чтобы данные между сервером и клиентом были зашифрованы, особенно если это чувствительная информация. Чтобы перейти на wss://, нужно настроить SSL:

import { createServer } from 'https'; import { readFileSync } from 'fs'; import { WebSocketServer } from 'ws';  const server = createServer({   cert: readFileSync('path/to/cert.pem'),   key: readFileSync('path/to/key.pem') });  const wss = new WebSocketServer({ server });  wss.on('connection', (ws) => {   ws.on('message', (message) => {     console.log(`Received: ${message}`);   });   ws.send('Secure connection established!'); });  server.listen(8080);

Теперь сервер использует защищенные соединения.

Оптимизация и масштабирование

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

Широковещательные сообщения

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

wss.on('message', (message) => {   wss.clients.forEach((client) => {     if (client.readyState === WebSocket.OPEN) {       client.send(message);     }   }); });

Масштабирование с Redis

Можно синхронизировать несколько серверов через Redis Pub/Sub, чтобы сообщения отправлялись на все экземпляры WebSocket сервера:

import Redis from 'ioredis';  const redis = new Redis(); const sub = new Redis();  sub.subscribe('messages'); sub.on('message', (channel, message) => {   wss.clients.forEach((client) => {     client.send(message);   }); });  wss.on('connection', (ws) => {   ws.on('message', (message) => {     redis.publish('messages', message);   }); });

Таким образом, клиенты, подключенные к разным серверам, могут обмениваться сообщениями через Redis.


Заключение

WebSocket — это невероятно мощный инструмент для создания real-time приложений, но, как и в любом деле, чтобы стать мастером, нужно идти дальше. Так что, если вам показалось, что этого мало (а это точно так), вот вам несколько идей, чем можно заняться дальше:

  1. Реализуй чат с историей сообщений — каждый клиент, подключаясь, может получать последние 50 сообщений, даже если он пропустил живое общение.

  2. Работа с WebSocket в продакшене — изучи, как лучше мониторить и перезагружать WebSocket серверы, например, с помощью PM2 или Kubernetes.

  3. Веб-сокеты и микросервисы — попробуй организовать обмен данными через WebSocket в архитектуре микросервисов, когда один сервис передает информацию другим.

Теперь, когда есть эти основы, всё зависит от вас. Исследуйте документацию, читайте статьи на Хабре, экспериментируйте с кодом, развивайте свои навыки — и создавайте что-то по-настоящему крутое.

А еще приходите на бесплатный захватывающий вебинар посвященный изучению мощного фреймворка разработки веб-приложений Nest.Js. Зарегистрироваться.


ссылка на оригинал статьи https://habr.com/ru/articles/851504/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *