Введение в Sockets.IO в Node.js
Сокеты.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 reloadingupvote_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 reloadingupvote_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