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

Что такое Socket.IO?

Socket.IO был создан в 2010 году. Он был разработан для использования открытых соединений для облегчения связи в реальном времени, что в то время было относительно новым явлением.

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

Для установления соединения и обмена данными между клиентом и сервером Socket.IO использует Engine.IO. Это низкоуровневая реализация, используемая под капотом. Для серверной реализации используется Engine.IO, для клиента — Engine.IO-client.

Как работает Socket.IO

Socket.IO напоминает WebSockets. WebSockets также являются реализацией браузера, обеспечивающей двунаправленную связь, однако Socket.IO не использует это в качестве стандарта. Во-первых, Socket.IO создает соединение с длительным опросом, используя xhr-polling. Затем, как только это установлено, он обновляется до наилучшего доступного метода подключения. В большинстве случаев это приведет к подключению через WebSocket. Узнайте, как веб-сокеты справляются с длительным опросом (и почему веб-сокеты почти всегда являются лучшим выбором), здесь, в блоге Ably. Полный обзор веб-сокетов, их истории, принципов работы и вариантов использования можно прочитать здесь.

Socket.IO — в действии

Популярным способом демонстрации двусторонней связи, которую обеспечивает Socket.IO, является базовое приложение для чата (о некоторых других вариантах использования мы поговорим ниже). С сокетами, когда сервер получает новое сообщение, он отправляет его клиенту и уведомляет его, минуя необходимость отправки запросов между клиентом и сервером. Простое приложение для чата показывает, как это работает.

Пример — Socket.IO для чата

Сервер

Вам нужно будет установить node.js. Мы будем использовать экспресс для упрощения настройки.

Создайте новую папку с:

Shell scriptmkdir socket.io-example
cd socket.io-example
npm install socket.io express

Настройте сервер и импортируйте необходимые пакеты.

Node.jsconst app = require("express")();
const http = require("http").createServer(app);
const io = require("socket.io")(http);

Корень сервера отправит наш index.html, который мы вскоре настроим.

Node.jsapp.get("/", (req, res) => res.sendFile(__dirname + "/index.html"));

Здесь мы настраиваем Socket.IO. Он прослушивает событие «соединение» и запускает предоставленную функцию в любое время, когда это происходит.

Node.jsio.on("connection", function(socket) {
 console.log(“socket connected”);
});

Это настроит сервер для прослушивания порта 3000.

Node.jshttp.listen(3000, () => console.log("listening on http://localhost:3000"));

Запустите приложение с помощью node index.js и откройте страницу в браузере.

Клиент

Включите следующие сценарии на свою страницу перед закрывающим тегом </body>. Теперь у вас есть настройка подключения к сокету.

JS<script src="/socket.io/socket.io.js"></script>
<script>
 const socket = io();
</script>

Это минимальная настройка для работы соединения Socket.IO. Давайте пойдем немного дальше, чтобы сообщения отправлялись туда и обратно.

Сервер

Внутри функции мы используем io.emit() для отправки сообщения всем подключенным клиентам. Этот код будет уведомлять, когда пользователь подключается к серверу.

Node.jsio.on("connection", function(socket) {
 io.emit(“user connected”);
});

Если вы хотите транслировать всем, кроме того, кто подключился, вы можете использовать
socket.broadcast.emit().

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

Node.jsio.on("connection", function(socket) {
 io.emit(“user connected”);
 socket.on(“message", function(msg) {
   io.emit("message", msg);
 });
});

Ниже показано, как добавить эти события в клиент.

Клиент

Вот файл index.html, который включает в себя наши предыдущие скрипты, простую форму с вводом для новых сообщений и контейнер для отображения сообщений.

JS<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <meta http-equiv="X-UA-Compatible" content="ie=edge" />
   <title>Socket.io Example</title>
 </head>
 <body>
   <h1>Our Socket.io Chat Application</h1>
   <div>
     <h2>Messages</h2>
     <ul></ul>
   </div>
   <form action="">
     <input type="text" />
     <button>Send</button>
   </form>
   <script src="/socket.io/socket.io.js"></script>
   <script>
     const socket = io();
   </script>
 </body>
</html>

Теперь мы добавим дополнительную логику в наш файл <script>.

JS<script>
 // select relevant elements
 const form = document.querySelector("form");
 const input = document.querySelector("input");
 messageList = document.querySelector("ul");
 // establish socket.io connection
 const socket = io();
 // handle sending message to server & input reset
 function sendMessage(e) {
   // prevent form submission refreshing page
   e.preventDefault();
   // send input value to server as type 'message'
   socket.emit("message", input.value);
   // reset input value
   input.value = "";
 }
 // add listener to form submission
 form.addEventListener("submit", sendMessage);
 // add message to our page
 function addMessageToHTML(message) {
   // create a new li element
   const li = document.createElement("li");
   // add message to the elements text
   li.innerText = message;
   // add to list of messages
   messageList.append(li);
 }
  // watch for socket to emit a 'message'
 socket.on("message", addMessageToHTML);
 // display message when a user connects
 function alertUserConnected() {
   addMessageToHTML("User connected");
 }
  // watch for socket to emit a 'user connected' event
 socket.on("user connected", alertUserConnected);
</script>

Ключевыми моментами здесь являются socket.on(event, callback) функции. Когда наш сервер выдает события, соответствующие первому аргументу «event», будет запущен обратный вызов. Внутри этих обратных вызовов мы можем выполнять нужные действия на стороне клиента. В данном случае вывод сообщения на экран.

Обслуживание и эксплуатация Socket.IO

Как объяснялось выше, начать работу с Socket.IO относительно просто — все, что вам нужно, это сервер Node.js для его запуска. Если вы хотите начать работу с приложением реального времени для ограниченного числа пользователей, Socket.IO — хороший вариант. Проблемы возникают при работе в масштабе. Скажем, например, вы хотите создать приложение, похожее на CRM, которое обеспечивает связь между предприятиями. Socket.IO построен на асинхронных сетевых библиотеках и вызовет нагрузку на ваш сервер. Поддержание соединений с пользователями, а также отправка и получение сообщений увеличивает нагрузку, и если клиенты начинают отправлять значительные объемы данных через Socket.IO, он передает данные фрагментами, высвобождая ресурсы при передаче фрагмента данных. Поэтому, когда ваше приложение привлекает больше пользователей и ваш сервер достигает максимальной нагрузки, вам нужно будет разделить соединения между несколькими серверами, иначе вы рискуете потерять важную информацию.

К сожалению, это не так просто, как добавить еще один сервер. Сокеты — это открытое соединение между сервером и клиентом. Сервер знает только о клиентах, которые подключились напрямую к нему, а не о тех, кто подключен к другим серверам. Возвращаясь к функции беседы, представьте, что вы хотите передать всем пользователям сообщение о том, что кто-то присоединился к чату. Если они подключены к другому серверу, они не получат это сообщение.

Чтобы решить эту проблему, вам нужно иметь pub/sub store (например, Redis). Этот магазин решит вышеупомянутую проблему, уведомив все серверы о том, что им нужно отправить сообщение, когда кто-то присоединяется к чату. К сожалению, это означает необходимость обслуживания дополнительной базы данных, для которой, скорее всего, потребуется собственный сервер.

Socket.IO создал адаптер socket.io-adapter, который работает с магазином pub/sub и серверами для обмена информацией. Вы можете написать собственную реализацию этого адаптера или использовать ту, которую они предоставили для Redis, с которой, к счастью, легко интегрируется Socket.IO.

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

Еще одна проблема с масштабированием Socket.IO заключается в том, что пока веб-сокеты удерживают свое соединение открытым, если соединение возвращается к опросу, то в течение времени существования соединения возникает несколько запросов. Когда один из этих запросов отправляется на другой сервер, вы получите сообщение об ошибке «Ошибка во время рукопожатия WebSocket: Неожиданный код ответа: 400».

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

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

Когда Socket.IO достигает своих пределов?

Как и в случае со всеми технологиями, правильный выбор означает четкое представление о ваших амбициях в отношении вашего продукта. Socket.IO действительно упрощает многие вещи по сравнению с самостоятельной настройкой сокетов, но в дополнение к упомянутой выше проблеме масштабирования существуют ограничения и недостатки.

Во-первых, начальное соединение длиннее по сравнению с WebSockets. Это связано с тем, что сначала устанавливается соединение с использованием длительного опроса и xhr-опроса, а затем выполняется обновление до веб-сокетов, если они доступны.

Если вам не нужна поддержка старых браузеров и вы не беспокоитесь о клиентских средах, которые не поддерживают WebSockets, возможно, вам не нужны дополнительные накладные расходы на Socket.IO. Вы можете свести к минимуму это влияние, указав подключение только с помощью веб-сокетов. Это изменит начальное подключение к WebSocket, но удалит любой запасной вариант.

Клиент

Node.jsConst socket = io({transports: [“websocket”], upgrade: false});

Сервер

Node.jsio.set("transports", ["websocket"]);

В этом сценарии клиенту по-прежнему потребуется загрузить файл JavaScript размером 61,2 КБ socket.io. Размер этого файла 61,2 КБ. Подробнее об этом процессе — здесь.

Для потоковой передачи данных, которые по определению являются тяжелыми, например потокового видео, сокеты не являются решением. Если вы хотите поддерживать обмен данными на этом уровне, лучшее решение — это webRTC или потоковая передача данных в качестве поставщика услуг, Ably — один из нескольких.

Socket.IO — будущее?

Socket.IO не поддерживается активно. Последний коммит был примерно 3 месяца назад, и большая часть кодовой базы была свободна от новых коммитов гораздо дольше. Кроме того, в настоящее время существует 384 открытых вопроса. Для тех, кто начинает новый проект с сокетами, важно, будет ли по-прежнему поддерживаться Socket.IO. На момент написания (июль 2019 г.) ситуация неясна, если не считать приведенной ниже информации. Если у вас есть дополнительная информация, свяжитесь.

Глядя на загрузки NPM, использование Socket.IO увеличивается, но только постепенно.

С другой стороны, Sockjs и WS неуклонно растут и опережают Socket.IO по количеству загрузок NPM.

Это указывает на то, что хотя использование сокетов возросло, разработчики выбрали альтернативу Socket.IO. Некоторые выбрали такие пакеты, как WS или SockJS. Другие выбрали хостинговые решения, в которых сложность сообщений в реальном времени обрабатывается за вас, и многие из них используют модели Freemium.

Как вы можете видеть ниже, все современные браузеры теперь поддерживают WebSockets. Это отчасти сводит на нет потребность в пакете, который обрабатывает сокет-соединения в браузере, и объясняет рост популярности таких пакетов, как WS, которые обрабатывают сокет-соединения на стороне сервера, но полагаются на собственный API-интерфейс браузера для соединений и связи на стороне клиента. .

Заворачивать

Как мы уже выяснили, Socket.IO — отличный инструмент для разработчиков, желающих установить двунаправленные сокетные соединения между клиентом и сервером. Это значительно упрощает реализацию простых приложений, таких как чат. Socket.IO упрощает многие вещи и предоставляет запасные варианты для неподдерживаемых клиентов, но имеет свои недостатки.

Масштабирование приложений, пожалуй, самый сложный шаг в использовании сокетов, а реализация Socket.IO для соединений, отличных от WebSocket, еще больше усложняет этот процесс. Будущая поддержка Socket.IO также вызывает сомнения.

Помимо вопроса о будущей поддержке, использование socket.io действительно зависит от конкретного случая использования — для начала создания простых приложений реального времени socket.io работает хорошо. Благодаря широко распространенной поддержке WebSocket (в ответ на огромный рост спроса на приложения и услуги реального времени с момента создания Socket.IO в 2010 году) теперь есть больше возможностей для использования аналогичных пакетов, более близких к нативной реализации, поэтому стоит сравнить Socket. IO к ним, а также. Для более сложных приложений или приложений, которые, по вашему мнению, будут масштабироваться, будьте готовы добавить в свой стек другие технологии. Чтобы определить, на каком этапе находится ваше приложение с точки зрения будущего масштаба и потребностей в реальном времени, свяжитесь с инженерами Ably, работающими в реальном времени. Мы стремимся быть максимально беспристрастными.

дальнейшее чтение

Ably Realtime предоставляет облачную инфраструктуру и API, чтобы помочь разработчикам упростить сложную разработку в реальном времени. Мы упрощаем внедрение и масштабирование функций реального времени в приложениях или распространение потоков данных среди сторонних разработчиков в виде API-интерфейсов реального времени.