Создавайте приложения реального времени с помощью WebSocket

внешний интерфейс сервер браузер WebSocket

WebSocketТехнология постепенно совершенствовалась и принесла нам много удобства в производственной среде. В этой статье мы попытаемся сначала разъяснить основные принципы WebSocket, а затем описать, как его использовать на практике.


WebSocket не заменит полностью HTTP

Первое, что нужно прояснить, — это позиционирование WebSocket. WebSocket — это технология, основанная на HTTP, которая обеспечивает полнодуплексный обмен текстовыми и двоичными данными между клиентом и сервером. Здесь следует отметить несколько вещей:

  • Построен на HTTP. WebSocket необходимо установить HTTP-соединение, прежде чем клиент сможет инициировать запрос «рукопожатия» WebSocket.После успешного рукопожатия клиент и сервер могут взаимодействовать с WebSocket.
  • Обеспечить текст (текст) и двоичные данные (двоичные данные) два вида передачи данных
  • Полнодуплексная связь. Как только коммуникационное соединение WebSocket установлено, будь то клиент или браузер, любая сторона может отправлять сообщения другой стороне, то есть реализуется функция проталкивания данных от сервера к клиенту.

WebSocket был создан для удовлетворения постоянно растущих требований к интернет-коммуникациям в режиме реального времени. В традиционном Интернете для реализации связи в реальном времени (например, в веб-версии QQ) обычным способом является опрос. Через определенные промежутки времени браузер отправляет HTTP-запросы на сервер, а затем возвращает последние данные в браузер. Наиболее очевидным недостатком этого метода является необходимость непрерывной отправки запросов, что не только занимает полосу пропускания, но и ресурсы ЦП сервера (запросы должны приниматься без информации).

С этой точки зрения появление WebSocket имеет как минимум два преимущества перед чистым HTTP для связи в реальном времени:

  • Улучшена производительность в реальном времени. Пока установлено соединение WebSocket, состояние соединения может поддерживаться. При отправке сообщений не требуется дополнительный процесс установления соединения, и производительность связи в реальном времени значительно улучшена.
  • Общий трафик данных уменьшается, а заголовок WebSocket намного меньше, чем заголовок HTTP, особенно количество отправляемых сообщений велико, что позволит сэкономить значительный объем трафика данных.

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


WebSocket API

Первоначально являясь частью стандарта HTML5, WebSocket превратился в независимый стандарт протокола. На стороне клиента HTML5 предоставляет нам очень чистый API.

Метод строительства

WebSocket(url: string, protocols?: string[] | string)
  • URL-адрес 表示要连接的 URL。注意协议名是wsилиwss.
  • протоколы Может быть одной строкой имени протокола или массивом из нескольких строк имен протокола. Эти строки используются для представления подпротоколов, что позволяет серверу реализовать несколько подпротоколов WebSocket (например, вы можете указать разные протоколы для обработки разных типов взаимодействий). Если этот параметр не указан, по умолчанию будет пустая строка.

Метод прототипа

Всего их всего два.

close(code?: number, reason?: string): void

Закройте соединение WebSocket или остановите текущий запрос на соединение. Если состояние соединения уже закрыто, этот метод не действует.

  • код Указывает номер состояния закрытого соединения, указывающий причину закрытия соединения. Если этот параметр не указан, значение по умолчанию равно 1000, что означает нормальное закрытие соединения. Посмотреть больше значенийCloseEventстраница.
  • причина Описательная строка, указывающая, почему соединение было закрыто.
send(data: string | ArrayBuffer | Blob): void

Отправка данных на сервер через соединение WebSocket.

  • data представляет данные для отправки на сервер, которые могут быть String,ArrayBufferилиBlobТипы. Строковый тип эквивалентен текстовым данным, ArrayBuffer и Blob — двоичным данным.

мероприятие

События следуют двум способам написания на родном Javascript:

  • onevent = handler
  • addEventListener(event, handler)

Поддерживаемые событияopen,message,closeа такжеerror. УведомлениеmessageСобытие срабатывает, когда все данные получены.

Атрибуты

Свойства объекта WebSocket используются для описания сведений о связи и состояния.

  • binaryType: stringУказывает тип содержимого, передаваемого в двоичном формате. Значение должно быть'blob'или'arraybuffer'

    var ws = new WebSocket('wss://example.com/socket');
    ws.binaryType = "arraybuffer"; // 强制将接收的二进制数据转为 ArrayBuffer 类型
    
    ws.onmessage = function(msg) {
      if(msg.data instanceof ArrayBuffer) {
        processArrayBuffer(msg.data);
      } else {
        processText(msg.data);
      }
    }
    
  • bufferedAmount: numberпередачаsend()Метод ставит в очередь многобайтовые данные для передачи, но еще не выдал их. Значение сбрасывается на 0 после отправки всех данных очереди. Он не будет установлен на 0, когда соединение будет закрыто. Если вы продолжаете звонитьsend(), это значение будет продолжать расти. Только чтение.

  • protocol: stringСтрока, указывающая имя подпротокола, выбранного сервером. Значение этого свойства передается в конструкторprotocolsпараметр или один из них.

  • readyState: numberТекущее состояние соединения. Значение является одной из констант состояния готовности. Только чтение.

  • url: stringURL-адрес, переданный в конструктор. Это должен быть абсолютный URL. Только чтение.

самый простой пример

// Create WebSocket connection.
const socket = new WebSocket('ws://localhost:8080');

// Connection opened
socket.addEventListener('open', function (event) {
  socket.send('Hello Server!');
});

// Listen for messages
socket.addEventListener('message', function (event) {
  console.log('Message from server', event.data);
});

Однако описанное выше реализовано только на клиентском веб-сокете, без взаимодействия с сервером веб-сокет не может обмениваться данными. Существуют различные схемы реализации WebSocket на стороне сервера, которые будут реализованы на Node.js в следующем разделе.

Вышеупомянутая часть является личным резюме, если вы хотите узнать больше о его API, вы можете обратиться к нему.Документация по MDN.


Базовое использование WebSocket

Использование WebSocket на самом деле не сложно, в этом разделе будут объединеныsocket.ioмодули объясняются. Давайте посмотрим, как создать простейшее приложение WebSocket.

Первый шаг — установить библиотеку зависимостей:

npm install socket.io express

Второй шаг, сборка клиента /public/index.html:

<body>
  <script src="/socket.io/socket.io.js"></script>
  <script>
    const socket = io('http://localhost:3231');
    socket.on('connect', () => {
      socket.emit('greet', 'Hello, websocket!');
      socket.on('uppergreet', data => console.log(data));
    });
  </script>
</body>

Обратите внимание на способ представления socket.io выше, не сомневайтесь в правильности пути, потому что socket.io автоматически импортирует соответствующий клиентский код и выставитioглобальные переменные.

Третий шаг, сборка сервера server.js:

const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const port = process.env.PORT || 3000;

app.use(express.static(__dirname + '/public'));

io.on('connection', socket => {
  socket.on('greet', data => socket.emit('uppergreet', data.toUpperCase()));
});

http.listen(port, () => console.log('listening on port ' + port));

Наконец, запуститеnode server.jsи доступ к нему через браузерhttp://localhost:3000, откройте консоль и вы увидите вывод:

HELLO, WEBSOCKET!

Можно заметить, что в методе написания с использованием socket.io для создания приложения WebSocket все еще существует большая разница по сравнению с API WebSocket, упомянутым в предыдущем разделе.

В дополнение к модулю socket.io, упомянутому в этом разделе, существуют различные реализации на Node.js, такие какwebsocketа такжеnodejs-websocket, они не только реализовали протокол связи WebSocket сервера, но и более-менее инкапсулировали WebSocket API клиента, о котором говорилось в предыдущем разделе, а функции были значительно улучшены, что нашло широкое применение в практической работе. сравнение Склоняюсь к библиотеке socket.io.


Применимые сценарии WebSocket

WebSocket подходит для сценариев, требующих эффективного общения в реальном времени, таких как веб-чат, боевые игры и т. д. В этом разделе будет использоватьсяsocket.ioМодули объясняются.На официальном сайте socket.io есть несколько типичных сценариев использования.Здесь мы используем более простой, предоставленный официальным сайтом.Корпус монтажной областиБыть объясненным. Официальный сайт socket.io также даетПример приложения для чата, разработанного с помощью jQuery, я реализовал в соответствии с его окончательным эффектомреактивная версия.

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

Первый — это серверный код index.js, который очень похож на код из предыдущего раздела:

const express = require('express');
const app = express();
const http = require('http').Server(app);
const io = require('socket.io')(http);
const port = process.env.PORT || 3000;

app.use(express.static(__dirname + '/public'));

io.on('connection', socket => {
  socket.on('drawing', data => socket.broadcast.emit('drawing', data));
});

http.listen(port, () => console.log('listening on port ' + port));

Затем выполните следующую команду:

node index.js

Затем откройте оба окна браузера и посетитеhttp://localhost:3000, а затем рисовать в одном браузере, а другой браузер может видеть результаты в режиме реального времени.

Вы можете видеть, что код на стороне сервера очень лаконичен, и ключевые шаги здесьconnectionМетод обработчика события внутри методаsocketбудет контролироватьdrawingмероприятие, прослушиваниеdrawingВ callback-функции после события снова транслироватьdrawingСобытия, вещание означает, что они отправляются всем клиентам, подключенным к серверу.

Тогда есть код ключа клиента /public/main.js:

var socket = io();
socket.on('drawing', onDrawingEvent);

var canvas = document.getElementsByClassName('whiteboard')[0];
canvas.addEventListener('mousedown', onMouseDown, false);
canvas.addEventListener('mouseup', onMouseUp, false);
canvas.addEventListener('mouseout', onMouseUp, false);
canvas.addEventListener('mousemove', throttle(onMouseMove, 10), false);

в коде вышеonDrawingEvent,mouseUpа такжеonMouseMoveКлюч вызывается внутри методаdrawLineметод:

function drawLine(x0, y0, x1, y1, color, emit){
  // ... 绘制 canvas ...

  if (!emit) return;

  socket.emit('drawing', {
    // ... 绘制 canvas 的状态信息 ...
  });
}

drawLineметод в зависимости от поступающихemitбит, чтобы определить, отправлять ли на серверdrawingСобытие, если оно нарисовано самим клиентом, отправить его на серверdrawingсобытие, иначе нет.

Вышеизложенное является общей идеей реализации приложения реального времени, в котором несколько человек рисуют одновременно.Можно увидеть, что когда мы используем WebSocket для связи, особенно при использовании библиотеки инструментов с высокой степенью инкапсуляции, такой как socket.io, процесс коммуникации очень прост Мы можем вложить большую часть нашей энергии в бизнес-логику.


Развитие технологии WebSocket позволило разработчикам реализовать логику связи в реальном времени, не понимая внутренностей протокола, особенно при использовании Node.js в качестве сервера. Библиотека инструментов, аналогичная socket.io, предоставляет очень удобный инструмент как для сервера, и клиент Вызов метода очень быстрый, чтобы начать работу. Если вам нужно создавать эффективные приложения реального времени на работе, WebSocket будет лучшим выбором.


использованная литература