Привет, Хабр!
Сегодня создадим свой 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 приложений, но, как и в любом деле, чтобы стать мастером, нужно идти дальше. Так что, если вам показалось, что этого мало (а это точно так), вот вам несколько идей, чем можно заняться дальше:
-
Реализуй чат с историей сообщений — каждый клиент, подключаясь, может получать последние 50 сообщений, даже если он пропустил живое общение.
-
Работа с WebSocket в продакшене — изучи, как лучше мониторить и перезагружать WebSocket серверы, например, с помощью PM2 или Kubernetes.
-
Веб-сокеты и микросервисы — попробуй организовать обмен данными через WebSocket в архитектуре микросервисов, когда один сервис передает информацию другим.
Теперь, когда есть эти основы, всё зависит от вас. Исследуйте документацию, читайте статьи на Хабре, экспериментируйте с кодом, развивайте свои навыки — и создавайте что-то по-настоящему крутое.
А еще приходите на бесплатный захватывающий вебинар посвященный изучению мощного фреймворка разработки веб-приложений Nest.Js. Зарегистрироваться.
ссылка на оригинал статьи https://habr.com/ru/articles/851504/
Добавить комментарий