Учебник по Socket.io с JavaScript

Нажмите здесь, чтобы опубликовать эту статью в LinkedIn »

WebSockets могут быть очень полезны для создания приложений для обмена данными в реальном времени или потоковой передачи данных в Интернете, таких как приложения для чата и приложения для потоковой передачи изображений или других типов мультимедиа. Кроме того, вы можете легко настроить соединение с любой конечной точкой сокета, используя JavaScript WebSocket API вашего браузера.

В этом руководстве мы собираемся создать простое приложение для чата на основе WebSockets с помощью socket.io и React. Как всегда, полный исходный код доступен здесь.

Почему WebSockets вместо HTTP (S)?

С помощью WebSockets вы можете установить постоянное соединение, которое обеспечивает двунаправленную связь между клиентом и сервером. В настоящее время в Интернете вы в основном найдете API-интерфейсы на основе REST, которые построены на HTTP. Эти API используются следующим образом: клиент запрашивает страницу или ресурс, а сервер отвечает (запрос-ответ). Таким образом, использование WebSockets поверх HTTP может иметь следующие преимущества:

1. Связь в реальном времени

В сценарии «запрос-ответ» сервер не может отправлять данные клиенту, если клиент не запросит что-то первым. Клиенту придется постоянно запрашивать изменения через равные промежутки времени (опрос), что мы не рассматриваем в режиме реального времени. Представьте себе приложение для чата, в котором вы будете видеть новые сообщения только каждые 30 секунд. Довольно раздражает…

У сервера есть способы уведомить клиента о новых событиях через HTTP-сообщения. Вы можете отправлять сообщения работнику службы, работающему в браузере клиента, или подписать клиента на события, отправленные сервером (SSE). Однако с WebSockets мы получаем эту функцию бесплатно и можем легко транслировать новые сообщения, полученные всем другим подключенным клиентам.

2. Меньше накладных расходов

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

Более того, HTTP-соединение обычно сохраняется только для определенного количества запросов и закрывается после некоторого времени бездействия. Таким образом, соединения придется повторно устанавливать довольно часто, что требует времени начальной настройки из-за трехстороннего установления связи TCP (и обмена сертификатом и парами ключей в случае HTTPS).

3. Потоковая обработка

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

Я думаю, вы понимаете, почему WebSockets могут быть полезны…

Давайте, наконец, напишем приложение!

Для этого мы будем использовать npm-пакет socket.io, который предоставляет нам node.js WebSocket API для нашего чат-сервера и клиент JavaScript для стороны браузера. Таким образом, нам не придется возиться с отправкой реальных двоичных данных, поскольку этот пакет любезно сериализует наши данные в JSON.

Далее я подробно рассмотрю весь исходный код. Я сосредоточусь на интересных моментах приложения, чтобы познакомить вас с socket.io.

Итак, что мы будем строить?

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

Давайте начнем!

Прослушивание входящих соединений через сокеты

В этом примере мы подключим socket.io к простому HTTP-серверу. Если вы хотите, вы также можете легко использовать socket.io вместе с express.

С помощью io.on (‘connection’, cb) мы прослушиваем входящие соединения сокетов. После подключения нового клиента мы можем подключить к потоку несколько прослушивателей событий. События ошибка и разъединение являются предопределенными. Другие события - это настраиваемые события, которые я ввел для реализации API чата.

Сервер ожидает подключения клиентов сокетов к порту 3000, что мы и сделаем ниже.

Подключение к серверу сокетов с помощью клиента

Обратите внимание: на стороне клиента нам нужен socket.io-client. Если вы не используете сборщик (я использую здесь webpack), вам нужно будет включить клиентский скрипт io в свой документ.

В нашем клиенте мы можем прослушивать события с помощью socket.on и удалять прослушиватель событий с помощью socket.off соответственно. . Позже мы будем использовать registerHandler для регистрации обратного вызова onMessageReceived в нашем чате компонент, чтобы обновлять состояние компонентов и отображать новые сообщения после получения.

С помощью socket.emit мы можем генерировать настраиваемые события, которые прослушивает наш чат-сервер. В качестве второго аргумента мы можем передать фактические данные. Кроме того, мы даже можем реализовать связь типа запрос-ответ, передав обратный вызов в качестве третьего аргумента, который мы можем использовать для получения ответа от сервера чата после отправки события на клиенте или наоборот. Это довольно удобно, и мы будем использовать это довольно часто в дальнейшем в этом примере.

Реализация API

На нашем сервере чата мы будем отслеживать всех подключенных клиентов и выбранный ими персонаж (ClientManager), а также состояние каждого чата, например список пользователей, присоединившихся к чату, и история всех сообщений, отправленных в этот чат (ChatroomManager).

Первое, что мы хотим добавить, это конечная точка для клиента, чтобы выбрать один из символов:

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

Более интересные вещи происходят, когда пользователь присоединяется, выходит из чата или отправляет сообщение. Соответствующие обработчики этих событий используют следующую вспомогательную функцию:

Это гарантирует, что переданный чат действителен и что персонаж был выбран заранее и «пользователь покинул / присоединился к чату» или сообщение, отправленное пользователем, добавлено в чат. история чата. Кроме того, мы транслируем событие всем пользователям в чате.

Реализовать чат довольно просто:

Для простоты chatHistory - это просто массив, и мы храним сопоставление всех пользователей в этом чате, чтобы мы могли выдать «сообщение для всех клиентов в broadcastMessage.

Поскольку фактические обработчики похожи друг на друга по функциональности, я покажу здесь только обработчик соединения:

После обработки события мы добавляем пользователя в чат и отвечаем текущей историей чата.

Наконец, как только клиент отключается, мы также убеждаемся, что удалили пользователя из всех чатов и удалили информацию о клиенте, что освободит выбор персонажа для других пользователей:

Отображение сообщений в реальном времени на клиенте

К нашему компоненту чата мы добавляем следующее:

При входе в новый чат мы инициализируем историю чата, возвращаемую сервером чата после получения события «присоединиться». Как и было обещано ранее, когда компонент монтируется, мы регистрируем обратный вызов onMessageReceived в обработчике из нашего клиентского API. После регистрации клиент будет получать сообщения о событиях, транслируемых сервером чата. Таким образом, мы можем обновить состояние компонентов новым сообщением и сразу же повторно отобразить активность чата.

Заключительные слова

Это уже обо всех интересных вещах, которые мы делаем здесь с WebSockets. Остальное - это просто создание пользовательского интерфейса с помощью React и material-ui. Так что, если вам это интересно, вы можете проверить исходный код. В остальном, я надеюсь, вы почувствуете себя уверенно с WebSockets и socket.io после прочтения этого руководства. Удачного кодирования!

Если вам понравилась эта статья, приглашаем вас оставить аплодисменты и подписаться на меня в среде и / или твиттере :). Также не стесняйтесь оставлять звездочку в репозитории github. Следите за новостями, чтобы увидеть больше уроков!