
Введение
Разработка эффективных и безопасных приложений требует не только хорошо продуманного API, но и правильного выбора протокола передачи данных. Веб-приложения обычно используют текстовые форматы, такие как JSON или XML, но для высокопроизводительных систем, требующих минимальной задержки и небольшого объема передачи данных, может быть выгодно использовать бинарные протоколы.
В этой статье мы рассмотрим, как разработать собственный бинарный протокол для приложений на основе Node.js и WebSockets, добавить авторизацию с помощью JWT и изучим преимущества бинарного протокола по сравнению с другими форматами данных.

Почему именно бинарный протокол?
Преимущества бинарного протокола:
Эффективность: Бинарные протоколы более компактны, чем текстовые форматы (например, JSON). Они позволяют передавать данные в более сжатом виде, что уменьшает объем передаваемого трафика.
Производительность: Благодаря меньшему объему данных и отсутствию необходимости в анализе текстовых форматов, бинарные протоколы экономят ресурсы как на стороне клиента, так и на стороне сервера.
Безопасность: Двоичные данные сложнее анализировать в режиме реального времени по сравнению с текстовыми данными, что делает двоичные протоколы менее уязвимыми для атак.
Гибкость: В бинарных протоколах форматы данных можно более точно контролировать для работы с конкретными типами данных (например, числами с плавающей запятой, строками, массивами байтов и т. д.).
Архитектура системы:
Мы разработаем систему, состоящую из следующих компонентов:
Сервер на Node.js, использующий WebSockets для связи с клиентами.
JavaScript -клиент, который подключается к серверу и использует бинарный протокол для передачи данных.
Авторизация с использованием JWT (JSON Web Token) для безопасного подключения клиентов к серверу.
Серверная реализация на Node.js
Установка зависимостей
Для начала установим необходимые зависимости:
npm init -y
npm install ws jsonwebtoken
Примечание: JWT можно также заменить на авторизацию внутри бинарного протокола, однако здесь будем использовать его для простоты понимания
ws — это библиотека для работы с WebSocket на стороне сервера, а jsonwebtoken — для работы с JWT.
Простой серверный код:
const WebSocket = require('ws');
const jwt = require('jsonwebtoken');
// Наш секретный ключ для JWT
const SECRET_KEY = 'your_secret_key';
// Создаем сервер
const wss = new WebSocket.Server({ port: 8080 });
// Верификация токена
function verifyJWT(token) {
try {
return jwt.verify(token, SECRET_KEY);
} catch (e) {
return null;
}
}
// Подключение к сокету
wss.on('connection', (ws, req) => {
// Получение токена из Header
const token = req.url.split('token=')[1];
const user = verifyJWT(token);
// Пользователь не авторизован
if (!user) {
ws.close(4001, 'Unauthorized');
return;
}
console.log(`User ${user.username} connected`);
ws.on('message', (message) => {
if (message instanceof Buffer) {
// Рабоа с бинарными сообщениями
const messageType = message.readUInt8(0); // Первый байт - тип сообщения
if (messageType === 1) {
const textLength = message.readUInt16BE(1);
const text = message.toString('utf-8', 3, 3 + textLength);
console.log(`Received message from ${user.username}: ${text}`);
} else if(messageType === 2) {
// Другие типы сообщений
}
}
});
ws.on('close', () => {
console.log(`User ${user.username} disconnected`);
});
});
console.log('WebSocket server started on ws://localhost:8080');
Пояснение к коду:
Авторизация с помощью JWT: Сервер проверяет токен JWT, переданный клиентом при подключении. Если токен недействителен, сервер закрывает соединение с ошибкой авторизации.
Обработка двоичных данных: В этом примере предполагается, что клиент отправляет двоичные данные. Сервер анализирует сообщение, считывая данные побайтно. Например, первый байт сообщения может использоваться в качестве типа сообщения, за которым следуют длина сообщения и сами данные.
Сервер WebSocket: библиотека ws используется для управления соединениями и сообщениями.
Внедрение клиентских решений
Клиентский код
Для реализации клиентской части мы используем чистый JavaScript.
// Создаем подключение к серверу
const socket = new WebSocket('ws://localhost:8080?token=your_jwt_token');
// Подключение установлено
socket.addEventListener('open', () => {
console.log('Connected to server');
// Пример бинарного сообщения
const message = "Hello, Binary World!";
const buffer = new ArrayBuffer(3 + message.length);
const view = new DataView(buffer);
view.setUint8(0, 1); // Устанавливаем тип сообщения
view.setUint16(1, message.length); // Устанавливаем длинну
for (let i = 0; i < message.length; i++) {
view.setUint8(3 + i, message.charCodeAt(i));
}
socket.send(buffer);
});
// Получание сообщение от сервера
socket.addEventListener('message', (event) => {
if (event.data instanceof Blob) {
event.data.arrayBuffer().then(buffer => {
const view = new DataView(buffer);
const messageType = view.getUint8(0);
if (messageType === 1) { // Тип сообщения
const textLength = view.getUint16(1);
const text = String.fromCharCode(...new Uint8Array(buffer.slice(3, 3 + textLength)));
console.log(`Received message: ${text}`);
}
});
}
});
// Закрытие соединения
socket.addEventListener('close', () => {
console.log('Disconnected from server');
});
Пояснение к коду:
Подключение к серверу: Клиент подключается к WebSocket серверу, передавая JWT-токен через строку запроса.
Отправка двоичных данных: Для отправки двоичных данных создается объект ArrayBuffer, в который записываются тип сообщения и текстовые данные.
Получение сообщений: Клиент ожидает от сервера двоичные данные и анализирует их, используя DataView для чтения байтов.
Создание и проверка JWT-токенов
Пример создания JWT-токена на стороне сервера:
const jwt = require('jsonwebtoken');
const SECRET_KEY = 'your_secret_key';
const token = jwt.sign({ username: 'user1' }, SECRET_KEY, { expiresIn: '1h' });
console.log(token);
Этот токен можно использовать для подключения клиента.
Заключение
Использование бинарного протокола в сочетании с WebSockets и авторизацией через JWT позволяет создать эффективную и безопасную систему для взаимодействия клиента и сервера. Бинарные протоколы, несмотря на сложность их реализации, обеспечивают значительные преимущества в производительности и сокращении объёма данных. Они особенно актуальны для приложений с высокой нагрузкой и интенсивным использованием ресурсов, где минимизация задержки и загрузки сети имеют важное значение.
Примеры готовых библиотек:
Этот подход может быть полезен для разработки игр, приложений с синхронизацией в реальном времени, финансовых приложений и других систем, требующих высокой производительности и надежности.
И, конечно же, спасибо за прочтение.
Комментарии (4)

goldexer
13.12.2025 20:35Итак, заголовок статьи начинается с «бинарные протоколы...», а в итоге в статье ни их названий, ни разновидностей, ни хитростей, тонкостей и секретов, ни даже приложения, которое бы реализовало пару видов реальных бинарных протоколов. Зато АИшный выхлоп с кодом уровня «пример для детей из учебника по JS» вполне себе присутствует. Такое надо минусовать, но наверно сейчас набегут «вау спасибо как удивительно и познавательно теперь мы всё знаем о бинарных протоколах» и люто заплюсуют. Хоть одной строчкой бы пару реальных названий - увы...
savostin
Да где ж он, этот бинарный протокол?
poznohub Автор
Ну вообще, подразумевается, что вместо использования передачи данных через JSON или аналогичных текстовых форматов, мы используем свои бинарные протоколы. Понятно, что я здесь просто описал просто введение, нежели полноценный протокол сообщений, который включает в себя еще как правило управление очередями и пирами, соединениями, нормальную систему типов данных. Как вариант можно посмотреть как это построено на gRPC, хотя там скорее сериализация, чем чистые протоколы.