SocketCluster — это среда JavaScript для создания приложений реального времени. Он обеспечивает масштабируемую и отказоустойчивую архитектуру для создания высокопроизводительных приложений реального времени.
Особенности кластера сокетов:
1 — обрабатывать неограниченное количество каналов
2 — Легкое развертывание
3 — Легко масштабировать
4 — Порядок сообщения гарантии
5 — Контролировать противодавление сообщений
…
Вы можете использовать клиентские библиотеки на языках C#, Golang, Javascript, Java и т. д.
Требования
- Node.js v10 (может работать со старыми версиями, но вы не сможете использовать цикл
for-await-of
для потребления потоков). Скачать Node.js.
Дополнительные зависимости
docker
CLI для контейнеризации. Установить Докер.kubectl
Интерфейс командной строки для развертывания. Установить Кубектл.
вы можете увидеть большую часть информации в этой ссылке.
[Сервер] Создать сервер
Аналогичная логика уже должна быть внутри server.js
при использовании шаблона по умолчанию:
// --- in server.js --- const http = require('http'); const socketClusterServer = require('socketcluster-server'); let options = { // ... }; let httpServer = http.createServer(); let agServer = socketClusterServer.attach(httpServer, options); // port 8000 httpServer.listen(8000);
Аргумент httpServer
должен быть экземпляром HTTP-сервера Node.js. Список возможных options
, которые можно передать экземпляру сервера SocketCluster, можно найти здесь. Обратите внимание, что вы также можете использовать синтаксис ECMAScript import
.
[Сервер] Прослушивание входящих сокетных соединений
Внутри server.js
вы можете найти цикл for-await-of
, который обрабатывает входящие подключения. Это должно выглядеть так:
// --- in server.js --- // SocketCluster/WebSocket connection handling loop. (async () => { for await (let {socket} of agServer.listener('connection')) { // Handle socket connection. } })();
[Клиент] Подключиться к серверу
Внутри public/index.html
клиент подключается к серверу следующим образом:
// --- in public/index.html --- let socket = socketClusterClient.create();
^ Если соединение установлено успешно, это приведет к тому, что цикл connection
на стороне сервера повторится один раз.
!! Вы можете передать объект options
функции socketClusterClient.create(...)
.
[Сервер] Прослушивание входящих сообщений на сокете
Вы можете использовать socket.receiver(...)
внутри цикла for-await-of
для обработки сообщений в сокете:
// --- in server.js --- // SocketCluster/WebSocket connection handling loop. (async () => { for await (let {socket} of agServer.listener('connection')) { (async () => { // Set up a loop to handle remote transmitted events. for await (let data of socket.receiver('customRemoteEvent')) { // ... } })(); } })();
!! Вы также можете перебирать поток socket.receiver(receiverName)
в клиентском сокете, используя тот же синтаксис.
[Клиент] передает сообщения через сокет
// --- in public/index.html --- // ... After the socket is created. socket.transmit('customRemoteEvent', 123);
^ Если сообщение достигает сервера, цикл customRemoteEvent
на стороне сервера повторяется один раз; data
будет 123
.
!! Вы также можете использовать тот же синтаксис для передачи из серверного сокета. Передача никогда не может быть неудачной, поэтому вам не нужно заключать ее в блок try-catch
.
[Сервер] Прослушивание входящих RPC на сокете
В отличие от сообщений, RPC ожидают ответа от другой стороны. Вы можете использовать socket.procedure(...)
в цикле for-await-of
для обработки RPC в сокете:
// --- in server.js --- // SocketCluster/WebSocket connection handling loop. (async () => { for await (let {socket} of agServer.listener('connection')) { (async () => { // Set up a loop to handle and respond to RPCs. for await (let request of socket.procedure('customProc')) { if (request.data && request.data.bad) { let badCustomError = new Error('Server failed to execute the procedure'); badCustomError.name = 'BadCustomError'; request.error(badCustomError); continue; } request.end('Success'); } })(); } })();
!! Вы также можете перебирать поток socket.procedure(procedureName)
в клиентском сокете, используя тот же синтаксис.
[Клиент] Вызывать RPC через сокет
// --- in public/index.html --- // ... After the socket is created. (async () => { let result = await socket.invoke('customProc', {foo: 'bar'}); // result will be 'Success' })();
!! Вы всегда должны добавлять блок try-catch
вокруг вызова socket.invoke(...)
для захвата асинхронных ошибок:
// --- in public/index.html --- // ... After the socket is created. (async () => { let result; try { result = await socket.invoke('customProc', {bad: true}); } catch (error) { // error will throw. // error.name will be 'BadCustomError'. } })();
!! Вы также можете использовать тот же синтаксис для серверных сокетов.
[Клиент] Подпишитесь на канал и следите за сообщениями
(async () => { let channel = socket.subscribe('foo'); for await (let data of channel) { // ... Handle channel data. } })();
[Клиент] Публиковать на канал, не дожидаясь подтверждения
// Publish data; do not wait for an acknowledgement from the server. socket.transmitPublish('foo', 'This is some data');
!! Вы также можете вызвать transmitPublish
для объекта AGChannel
; в этом случае следует опустить первый аргумент, например:
let fooChannel = socket.channel('foo'); fooChannel.transmitPublish('This is some data');
[Клиент] Публикация на канале и ожидание подтверждения
(async () => { try { // Publish data; wait for an acknowledgement from the server. await socket.invokePublish('foo', 'This is some more data'); } catch (error) { // ... Handle potential error if server does not acknowledge before timeout. } })();
!! Вы также можете вызвать invokePublish
для объекта AGChannel
; в этом случае следует опустить первый аргумент, например:
(async () => { let fooChannel = socket.channel('foo'); try { // Publish data; wait for an acknowledgement from the server. await fooChannel.invokePublish('This is some more data'); } catch (error) { // ... Handle potential error if server does not acknowledge before timeout. } })();
[Сервер] Публиковать на канал, не дожидаясь подтверждения
// Publish data; do not wait for an acknowledgement from the back end broker. agServer.exchange.transmitPublish('foo', 'This is some data');
[Сервер] Публикация на канале и ожидание подтверждения
(async () => { try { // Publish data; wait for an acknowledgement from the back end broker (if it exists). await agServer.exchange.invokePublish('foo', 'This is some more data'); } catch (error) { // ... Handle potential error if broker does not acknowledge before timeout. } })();