WebSocket¶
WebSocket - это протокол передачи данных, основанный на протоколе TCP обеспечивающий обмен сообщениями между клиентом и сервером в режиме реального времени.
Протокол WebSocket¶
Для установления соединения по WebSocket клиентская сторона сперва отправляет используя протокол HTTP специальные заголовки Upgrade и Connection, тем самым говоря, что она хочет перейти на общение по WebSocket. А сервер уже сам решает, разрешать установку соединения или нет.
Обмен сообщениями между сервером и клиентом осуществляется с помощью специальных пакетов, называемых фреймами. Выделяют два типа фреймов:
- Управляющие данными (посылают данные);
- Управляющие соединением (проверяют установку соединения через PING или закрывают его).
Node.js и socket.io¶
Для использования в Node.js WebSocket необходимо установить npm модуль socket.io.
1 | |
Рассмотрим пример.
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | |
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | |
Для подключения WebSocket на клиентской стороне используется модуль socket.io-client, экземпляру которого передается адрес сервера, с которым необходимо установить соединение по WebSocket.
При установке соединения между клиентом и сервером Node.js по WebSocket генерируется событие connection, которое обрабатывается с помощью метода on() модуля socket.io. Передаваемая вторым параметром методу on() callback-функция единственным параметром принимает экземпляр соединения (далее просто сокет).
1 | |
Каждое соединение имеет свой уникальный идентификатор, зная который можно отправить сообщение конкретному клиенту (см. в примере маршрут /client/:id).
При разрыве соединения генерируется событие disconnect. Соединение разрывается, когда пользователь закрывает вкладку или когда сервер вызывает у сокета метод disconnect().
1 | |
Для отправки данных от сервера Node.js к клиенту (и наоборот), используется метод emit(), которые принимает следующие параметры:
- имя события;
- данные, которые необходимо отправить (могут быть отправлены в виде REST-аргументов);
- callback-функция (передается последним параметром), которая будет вызвана, когда вторая сторона получит сообщение.
Обработка отправляемых данных на стороне получателя происходит с использованием уже знакомого метода on(), первым параметром принимающего имя события, указанного в emit(), вторым - callback-функцию с переданными данными в качестве ее параметров.
1 2 3 4 5 6 7 8 9 10 11 | |
Для отправки данных всем клиентам, используйте метод emit() применительно к объекту io.sockets.
1 | |
Чтобы узнать текущее количество соединений, используйте метод clients(), вызываемый применительно к свойству sockets экземпляра модуля socket.io (см. в примере маршрут /clients-count).
В качестве необязательного параметра методу clients() можно передать имя "комнаты", количество соединений для который вы хотите узнать.
Пространства и "комнаты"¶
В протоколе WebSocket существуют такие понятия, как пространства и "комнаты". По умолчанию посылаемые данные отправляются всем сокетам, но принимают эти данные лишь некоторые из них. Получается, что в определенные моменты времени будет установлено избыточное количество соединений. Чтобы избежать этого, используйте пространства.
Пространства позволяют изолировать одни сокеты от других.
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
1 | |
В приведенном примере с помощью метода of() на сервере определяются два пространства: /users и /orders. На клиентской стороне подключение к тому или иному пространству происходит в зависимости от текущего маршрута. Таким образом, при отправке данных, например, из пространства /users, об этом будут оповещены только сокеты этого пространства. По умолчанию все сокеты находятся в пространстве /.
Также и в пределах пространства можно распределять сокеты по так называемым "комнатам".
1 2 3 | |
Чтобы отнести сокет к определенной "комнате" используется метод пространства join(), который принимает имя "комнаты" (задается пользователем модуля socket.io). Для вынесения сокета из комнаты используйте метод leave().
Отправка данных в "комнату" осуществляется с помощью метода to().
1 | |
Обработка инициируемых в пределах "комнаты" событий осуществляется с использованием метода in().
1 2 3 | |