Введение в Sockets.IO в Node.js

Опубликовано: 4 Января, 2023

Сокеты.IO:

Раньше веб-сайты перезагружались каждый раз, когда запрашивался ресурс. Это привело к ненужным задержкам, которые увеличили среднее время ожидания. Часто пользователям приходилось ждать несколько минут, чтобы получить определенную страницу или файл. С другой стороны, приложения реального времени (мессенджеры, онлайн-игры, push-уведомления и т. д.) — это те приложения, которые запускаются в течение заданного временного интервала, так что пользователю предоставляется немедленная и актуальная копия ресурса. Задержка в этих приложениях поддерживается на минимально возможном уровне, чтобы обеспечить бесперебойную и последовательную работу пользователей. Socket.IO — одна из таких библиотек JavaScript, которую программисты используют при разработке «веб-приложений» в реальном времени.

Почему Sockets.IO:
Большинство приложений в Интернете сегодня основаны на архитектуре клиент-сервер. Клиент — это тот, кто запрашивает что-то с сервера. Сервер на основе запроса отвечает соответствующими результатами. Эти два объекта полностью отличаются друг от друга из-за характера задач, которые они выполняют. Браузер — прекрасный пример клиентского приложения. Клиенты в браузерах обычно общаются с серверами через HTTP-запросы и ответы. Проблема с этим общением заключается в том, что либо запрос, либо ответ могут быть отправлены одновременно. Для понимания подумайте об этом как о полудуплексном соединении. Кроме того, заголовки HTTP содержат много-много избыточной информации, которая бесполезна после установления соединения между клиентом и сервером. С другой стороны, сокеты работают на транспортном уровне сетевого стека. Не так много избыточных полей, что увеличивает эффективность передачи информации через Интернет.

Socket.IO работает по тому же принципу и обеспечивает двустороннюю связь между веб-клиентами и серверами. Для того, чтобы обрабатывать их по отдельности и эффективно, он состоит из двух частей;

  • клиентская библиотека JavaScript, работающая в браузерах.
  • сервер Node.js

Socket.IO опирается на Engine.IO, который является реализацией уровня двунаправленной связи между браузерами и устройствами на основе транспорта. Он добавляет в Socket.IO следующие функции:

  • Надежность: он может устанавливать соединение даже при наличии прокси-серверов, балансировщиков нагрузки, персональных брандмауэров и антивирусных программ.
  • Поддержка автоматического переподключения: если в коде явно не указано иное, клиентская библиотека будет пытаться переподключиться навсегда, пока сервер снова не будет доступен.
  • Обнаружение отключения: позволяет и серверу, и клиенту узнать, когда другой больше не отвечает.
  • Поддержка мультиплексирования: позволяет иметь несколько каналов связи на одном базовом соединении.
  • Поддержка двоичной потоковой передачи: она также позволяет передавать любые сериализуемые двоичные данные, такие как ArrayBuffer, Blob и т. д.

Установка:

    Требуется для установки Sockets.IO

  • Узел установлен
  • npm (менеджер пакетов узлов) установлен

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

  • Сервер:
    Чтобы установить его в проекте Node.js, выполните следующую команду:

     $ npm install --save socket.io
  • JavaScript-клиент:
    Автономная сборка клиента по умолчанию предоставляется сервером по адресу /socket.io/socket.io.js . В противном случае его также можно обслуживать от любого из провайдеров CDN.

    Чтобы использовать его из Node.js, установите его с помощью этой команды:

     $ npm install --save socket.io-client

Пример:

Этот пример посвящен реализации базовой кнопки Upvote в Socket.IO. Он покажет взаимодействие сервера и клиента в режиме реального времени. Для начала перейдите в нужный каталог проекта и инициализируйте его либо с помощью команды npm init , либо вручную создайте файл package.json .

{
“name”: “upvote-example”,
“version”: “0.1”,
“description”: “the very first socket.io app”,
“main”: “index.js”,
“dependencies”: {}
}

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

$ npm install --save express@4.15.2

После установки создайте файл index.js , который настроит приложение.

var app = require( ‘express’ )();
var http = require( ‘http’ ).createServer( app );

const PORT = 3000;

app.get( ‘/’, function( req, res ) {
res.send( ‘

Hello World

‘ );
});

http.listen( PORT, function() {
console.log( ‘listening on *:’ + PORT );
});

Что делает этот код, так это создает обработчик функции для Express, который затем передается на HTTP-сервер. Этот обработчик отвечает клиенту «Hello World» при запросе страницы / . Наконец, HTTP-сервер начинает прослушивать порт 3000.

Запуск будет выглядеть примерно так,

Обслуживание HTML:
Раньше в ответ на запрос GET отправлялась только одна строка HTML. На этот раз прикрепите файл HTML с помощью метода sendFile .

app.get( ‘/’, function( req, res ) {
res.sendFile( __dirname + ‘/public/index.html’ );
});

Теперь создайте файл index.html и вставьте следующий код.

Перезапустите проект и обновите страницу, она должна выглядеть примерно так,

Интеграция Socket.IO:
Для установки модуля на стороне сервера выполните следующую команду:

$ npm install --save socket.io

Теперь внесите изменения в index.js следующим образом:

var app = require( ‘express’ )();
var http = require( ‘http’ ).createServer( app );
var io = require( ‘socket.io’ )( http );

const PORT = 3000;

app.get( ‘/’, function( req, res ) {
res.sendFile( __dirname + ‘/public/index.html’ );
});

http.listen( PORT, function() {
console.log( ‘listening on *:’ + PORT );
});

io.on( ‘connection’, function( socket ) {
console.log( “a user has connected!” );
});

Дополнительные изменения инициализируют обработчик Socket.IO. Действие регистрации присоединяется к этому обработчику, когда он выдает сигнал «подключения».

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

<script src=”/socket.io/socket.io.js”></script>
<script>
var socket = io();
</script>

Снова перезапустите проект из консоли и попробуйте открыть локальный хост в нескольких вкладках и браузерах. Каждый из них будет действовать как уникальное клиентское соединение. Сообщение журнала будет печататься каждый раз при установлении соединения между клиентом и сервером.

Каждый сокет также запускает специальное событие разъединения , когда клиент закрывает или обновляет вкладку:

io.on( ‘connection’, function( socket ) {
console.log( ‘a user has connected!’ );
socket.on( ‘disconnect’, function() {
console.log( ‘user disconnected’ );
});
});

Выдача событий:
Основная идея Socket.IO заключается в том, что можно отправлять и получать любые события по выбору, с данными или без них. Подойдут любые объекты, которые могут быть закодированы как JSON, а также поддерживаются двоичные данные.

Предположим, что когда пользователь нажимает кнопку «за», генерируется событие с именем upvote-event . Итак, в файл index.html вставьте следующий скрипт.

<script src=”/socket.io/socket.io.js”></script>
<script>
var socket = io();
var btn = document.getElementById( ‘upvote-btn’ );
var upvote_val = false;

btn.addEventListener( ‘click’, function( e ) {
e.preventDefault(); // prevent page reloading

upvote_val = upvote_val ? false: true;

socket.emit( ‘upvote-event’, upvote_val );
});
</script>

И в index.js следующий фрагмент кода для регистрации данных события.

io.on( ‘connection’, function( socket ) {
console.log( ‘a user has connected!’ );

socket.on( ‘disconnect’, function() {
console.log( ‘user disconnected’ );
});

socket.on( ‘upvote-event’, function( upvote_flag ) {
console.log( ‘upvote: ‘ + upvote_flag );
});
});

Результат должен выглядеть примерно так,

Вещание:
Следующая цель — передать событие с сервера остальным пользователям. На этот раз количество голосов, основанное на кликах, будет транслироваться каждому клиенту, подключенному к серверу. Назовем это событие update-upvotes . Для подсчета голосов создадим переменную upvote-count . Обновите index.js следующим образом:

var upvote_count = 0;
io.on( ‘connection’, function( socket ) {
console.log( ‘a user has connected!’ );

socket.on( ‘disconnect’, function() {
console.log( ‘user disconnected’ );
});

socket.on( ‘upvote-event’, function( upvote_flag ) {
upvote_count += upvote_flag ? 1: -1;
var f_str = upvote_count + ( upvote_count == 1 ? ‘ upvote’: ‘ upvotes’);

io.emit( ‘update-upvotes’, f_str );
});
});

Здесь upvote_count инициализируется нулем (0) и обновляется на основе значения upvote_flag . Затем обновленное значение передается всем клиентам, включая тот, на котором произошло событие «обновление».

На стороне клиента обновите index.html следующим образом:

<script>
var socket = io();
var btn = document.getElementById( ‘upvote-btn’ );
var upvote_val = false;

btn.addEventListener( ‘click’, function( e ) {
e.preventDefault(); // prevent page reloading

upvote_val = upvote_val ? false: true;

socket.emit( ‘upvote-event’, upvote_val );
});

socket.on( ‘update-upvotes’, function( f_str ) {
document.getElementById( ‘upvote-count’ ).innerHTML = f_str;
});
</script>

Он будет обновлять элемент DOM текущим значением счетчика голосов. Результаты будут выглядеть так,


Есть много вещей, которые нужно учитывать, чтобы сделать этот пример надежным и пригодным для использования в реальной разработке. Следует учитывать тот факт, что этот пример столкнется с проблемой состояния гонки, когда несколько пользователей одновременно нажимают кнопку «за». Чтобы заставить его работать в реальных приложениях, следует использовать соответствующие механизмы блокировки.

Получение этого примера:
Полный код этого примера можно найти на Github здесь.

Git-репозиторий:

https://github.com/CherryGot/SocketIO-Upvote.git