С развитием веб-технологий сценарии использования и требования становятся все более сложными, и клиента уже не устраивает простой запрос на получение статуса. Связь в режиме реального времени все больше используется в различных сферах.
HTTP является наиболее часто используемой технологией связи между клиентом и сервером, но HTTP-связь может быть инициирована только клиентом и не может своевременно получать изменения данных на сервере. Вы можете полагаться только на периодический опрос, чтобы получить последний статус. Своевременность не может быть гарантирована, и большее количество запросов увеличит нагрузку на сервер.
Появилась технология WebSocket.
Концепция веб-сокета
В отличие от HTTP PROMI-DUPLEUPLEX WebSocket - это полнодуплексный протокол на основе подключения TCP, поддерживает двустороннюю связь сервера клиента.
WebSocket
Обмен данными между клиентом и сервером упрощается, что позволяет серверу активно передавать данные клиенту. В API WebSocket браузеру и серверам нужно только выполнить рукопожатие, и они могут создавать постоянные соединения и выполнять двустороннюю передачу данных.
существуетWebSocket API
, браузеру и серверу нужно только сделать рукопожатие, после чего между браузером и сервером формируется быстрый канал. Данные могут передаваться напрямую между ними.
выполнить
собственная реализация
Объект WebSocket поддерживает в общей сложности четыре сообщения onopen, onmessage, onclose и onerror.
установить соединение
Соединение WebSocket можно быстро установить с помощью javascript:
var Socket = new WebSocket(url, [protocol] );
Первый параметр в приведенном выше кодеurl
, указывает URL-адрес подключения. второй параметрprotocol
является необязательным и указывает допустимые подпротоколы.
Использовать с http-протоколомhttp://
Как и в начале, URL-адрес протокола WebSocket используетws://
В начале используется дополнительно безопасный протокол WebSocketwss://
начало.
- Когда соединение между браузером и WebSocketServer установлено успешно, будет запущено сообщение onopen.
Socket.onopen = function(evt) {};
- В случае сбоя соединения, сбоя отправки или получения данных или возникновения ошибки при обработке данных браузер выдает сообщение об ошибке.
Socket.onerror = function(evt) { };
- Когда браузер получает запрос на закрытие соединения, отправленный WebSocketServer, запускается сообщение о закрытии.
Socket.onclose = function(evt) { };
отправлять и получать сообщения
- Когда браузер получает данные, отправленные WebSocketServer, он инициирует сообщение onmessage, а параметр evt содержит данные, переданные сервером.
Socket.onmessage = function(evt) { };
- send используется для отправки сообщения на сервер.
Socket.send();
socket
WebSocket предлагался вместе с HTML5, поэтому есть проблема с совместимостью.В это время появилась очень полезная библиотека——Socket.io.
socket.io инкапсулирует websocket и включает в себя другие методы подключения.Вы можете использовать socket.io для установки асинхронных подключений в любом браузере. socket.io содержит библиотеку сервера и клиента.Если в браузере используется js socket.io, сервер также должен быть применим.
socket.io — это библиотека связи клиент-сервер в реальном времени, основанная на Websocket.
Нижний уровень socket.io основан на библиотеке engine.io. engine.io — это низкоуровневая библиотека для socket.io, обеспечивающая двунаправленную связь между браузерами и устройствами. engine.io использует Websocket и XHR для инкапсуляции набора протоколов сокетов. В более ранних версиях браузеров Websocket не поддерживается, и вместо него для совместимости используется длинный опрос.
Socket.io позволяет вам запускать пользовательские события или реагировать на них.Вы можете запускать любое пользовательское имя события, кроме подключения, сообщения и отключения, которые нельзя использовать.
установить соединение
const socket = io("ws://0.0.0.0:port"); // port为自己定义的端口号
let io = require("socket.io")(http);
io.on("connection", function(socket) {})
Обмен сообщениями
1. Отправка данных
socket.emit(自定义发送的字段, data);
2. Получить данные
socket.on(自定义发送的字段, function(data) {
console.log(data);
})
Отключить
1. Отключить все
let io = require("socket.io")(http);
io.close();
2. Клиент отключается от сервера
// 客户端
socket.emit("close", {});
// 服务端
socket.on("close", data => {
socket.disconnect(true);
});
Комната и пространство имен
Иногда вебсокет имеет следующие сценарии использования: 1. Сообщения, отправляемые сервером, классифицируются, и разные клиенты должны получать разные классификации 2. Серверу не нужно отправлять сообщения всем клиентам, только для определенного Отправлять сообщения определенным группы;
Для этого сценария использования используются очень практичное пространство имен и место в сокете.
Давайте сделаем снимок, чтобы увидеть связь между пространством имен и комнатой:
namespace
Сервер
io.of("/post").on("connection", function(socket) {
socket.emit("new message", { mess: `这是post的命名空间` });
});
io.of("/get").on("connection", function(socket) {
socket.emit("new message", { mess: `这是get的命名空间` });
});
клиент
// index.js
const socket = io("ws://0.0.0.0:****/post");
socket.on("new message", function(data) {
console.log('index',data);
}
//message.js
const socket = io("ws://0.0.0.0:****/get");
socket.on("new message", function(data) {
console.log('message',data);
}
room
клиент
//可用于客户端进入房间;
socket.join('room one');
//用于离开房间;
socket.leave('room one');
Сервер
io.sockets.on('connection',function(socket){
//提交者会被排除在外(即不会收到消息)
socket.broadcast.to('room one').emit('new messages', data);
// 向所有用户发送消息
io.sockets.to(data).emit("recive message", "hello,房间中的用户");
}
Пример получения информации в реальном времени с помощью socket.io
Наконец дошли до стадии применения, сервер используетnode.js
Мокайте интерфейс сервера. Следующие примеры реализованы на локальном сервере.
Сервер
Давайте сначала посмотрим на сервер, сначала запустим службу, установим ееexpress
а такжеsocket.io
Установить зависимости
npm install --Dev express
npm install --Dev socket.io
построить узел сервера
let app = require("express")();
let http = require("http").createServer(handler);
let io = require("socket.io")(http);
let fs = require("fs");
http.listen(port); //port:输入需要的端口号
function handler(req, res) {
fs.readFile(__dirname + "/index.html", function(err, data) {
if (err) {
res.writeHead(500);
return res.end("Error loading index.html");
}
res.writeHead(200);
res.end(data);
});
}
io.on("connection", function(socket) {
console.log('连接成功');
//连接成功之后发送消息
socket.emit("new message", { mess: `初始消息` });
});
клиент
Основной код - index.html (отправка данных на сервер)
<div>发送信息</div>
<input placeholder="请输入要发送的信息" />
<button onclick="postMessage()">发送</button>
// 接收到服务端传来的name匹配的消息
socket.on("new message", function(data) {
console.log(data);
});
function postMessage() {
socket.emit("recive message", {
message: content,
time: new Date()
});
messList.push({
message: content,
time: new Date()
});
}
Код ядра — message.html (получение данных с сервера)
socket.on("new message", function(data) {
console.log(data);
});
Эффект
эффект общения в реальном времени
Все клиенты отключены
Клиент отключается
приложение пространства имен
присоединиться к комнате
покинуть комнату
приложение в рамках
npm install socket.io-client
const socket = require('socket.io-client')('http://localhost:port');
componentDidMount() {
socket.on('login', (data) => {
console.log(data)
});
socket.on('add user', (data) => {
console.log(data)
});
socket.on('new message', (data) => {
console.log(data)
});
}
Анализ протокола webSocket
Headers
запросить пакет
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: Upgrade
Cookie: MEIQIA_VISIT_ID=1IcBRlE1mZhdVi1dEFNtGNAfjyG; token=0b81ffd758ea4a33e7724d9c67efbb26; io=ouI5Vqe7_WnIHlKnAAAG
Host: 0.0.0.0:2699
Origin: http://127.0.0.1:5500
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: PJS0iPLxrL0ueNPoAFUSiA==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1
Описание пакета запроса:
- Должен быть допустимый формат http-запроса;
- Метод HTTP-запроса должен быть GET, а протокол должен быть не ниже 1.1, например: Get / HTTP/1.1;
- Поле заголовка Upgrade должно быть включено, и его значение равно «websocket», чтобы сообщить серверу, что это соединение необходимо обновить до websocket;
- НЕОБХОДИМО включать поле заголовка «Соединение» со значением «Обновление»;
- ДОЛЖЕН включать поле заголовка «Sec-WebSocket-Key», значение которого представляет собой случайную последовательность символов длиной 16 байт, закодированную в base64;
- Если запрос исходит от клиента браузера, необходимо также включить поле заголовка Origin. Это поле заголовка используется для предотвращения несанкционированных атак с использованием междоменных сценариев, и сервер может решить, принимать ли соединение WebSocket от Origin;
- Должен включать поле заголовка «Sec-webSocket-Version», которое является номером версии используемого в настоящее время протокола, и текущее значение должно быть 13;
- Может включать «Sec-WebSocket-Protocol», указывающий список протоколов, поддерживаемых клиентом (приложением), и сервер выбирает один или ни одного приемлемого ответа протокола;
- Может включать «Sec-WebSocket-Extensions», расширения протокола, определенный тип протокола может поддерживать несколько расширений, с помощью которых могут быть достигнуты улучшения протокола;
- Может включать произвольные другие домены, такие как файлы cookie.
пакет ответа
Описание пакета ответа:
Connection: Upgrade
Sec-WebSocket-Accept: I4jyFwm0r1J8lrnD3yN+EvxTABQ=
Sec-WebSocket-Extensions: permessage-deflate
Upgrade: websocket
- Поле заголовка Upgrade должно быть включено со значением «websocket»;
- ДОЛЖЕН включать поле заголовка Connection со значением «Upgrade»;
- Должно быть включено поле заголовка Sec-WebSocket-Accept, значение которого является значением пакета запроса «Sec-WebSocket-Key», а строка «258EAFA5-E914-47DA-95CA-C5AB0DC85B11» конкатенирована, а затем конкатенированные символы Строка подвергается операции sha-1, а затем кодированию base64, что является значением "Sec-WebSocket-Accept";
- В ответном пакете после двоеточия есть пробел;
- Наконец, в конце пакета ответа требуются две пустые строки.
запросить данные
EIO: 3
transport: websocket
sid: 8Uehk2UumXoHVJRzAAAA
- EIO:3 указывает, что используется протокол engine.io версии 3.
- транспорт указывает тип используемого транспорта
- sid: идентификатор сеанса (строка)
Frames
Протокол WebSocket использует фреймы для отправки и получения данных, и вы можете просмотреть данные отправленных фреймов в консоли -> Фреймы.
Что означают цифры перед данными кадра?
Это протокол Engine.io, где числа — это кодировка пакета:
[]
-
0 open - отправляется с сервера при открытии нового транспорта (перепроверено)
-
1 close — Запрос на закрытие этого транспорта, но не самого соединения.
-
2 пинга - отправил клиент. Сервер должен ответить пакетом pong, содержащим те же данные.
Клиент отправляет: тестовый кадр 2probe
-
3 pong — отправляется сервером в ответ на пинг-пакет.
Сервер отправляет: 3probe, отвечает клиенту
-
4 сообщение - фактическое сообщение, клиент и сервер должны вызывать свои обратные вызовы с данными.
-
Обновление 5. Прежде чем Engine.io переключает транспорты, он проверяет, могут ли сервер и клиент обмениваться данными через этот транспорт. Если этот тест проходит успешно, клиент отправляет пакет обновления с просьбой к серверу сбросить кэш на старом транспорте и переключиться на новый транспорт.
-
6 noop - пакет noop. В основном используется для принудительного цикла опроса при получении входящего соединения WebSocket.
Пример
Приведенный выше снимок экрана является примером передачи данных в приведенном выше примере, и общий процесс выглядит следующим образом:
- подключить рукопожатие успешно
- Клиент отправит 2 тестовых кадра
- Сервер отправляет кадр ответа 3probe
- Клиент отправит кадр обновления с содержимым 5
- Сервер отвечает на кадр noop с содержимым 6
- После прохождения проверки детектирования клиент останавливает опрос, переводит канал передачи на вебсокет соединение, а после перехода на вебсокет начинает периодически пинг/понг (по умолчанию 25 секунд).
- Клиент и сервер отправляют и получают данные, 4 представляет сообщение сообщения engine.io, за которым следует содержимое отправленного и полученного сообщения.
Чтобы узнать, является ли соединение между клиентом и сервером нормальным, ClientSocket и ServerSocket, используемые в проекте, имеют поток сердцебиения. Этот поток в основном предназначен для определения того, нормально ли подключены клиент и сервер. в основном гарантируется процессом пинг-понга.
Интервал, с которым периодически отправляется пульс, составляет 25 м, установленный по умолчанию socket.io, что также можно наблюдать на рисунке выше. Этот интервал можно пройти черезнастроитьИсправлять.
Ссылаться наengine.io-protocol
Справочная статья
Краткий обзор технологии веб-передачи в реальном времени Подробное объяснение принципа engine.io
Кроме того, мы недавно открыли вакансии по набору персонала, добро пожаловать! >Рекрутинг Mint Front-End
Широкая реклама
Эта статья была опубликована вЕженедельный выпуск Mint Front End, Добро пожаловать в Watch & Star ★, пожалуйста, указывайте источник при перепечатке.