предисловие
Перед этой статьейWebSocket
Многие люди слышали о ней, никогда не видели и никогда не использовали. Они думают, что это технология очень высокого уровня. На самом деле, эта технология не загадочна. Можно сказать, что это технология, которую легко освоить. выкинь каштаны из текста и попробуй сам, и ты узнаешь правду.
Узнайте о плавании и фитнесе:блог,Документы внешнего накопления,Нет публики,GitHub
WebSocket
Какая проблема была решена:
Клиент (браузер) взаимодействует с сервером и может быть инициирован только клиентом.ajax
Можно передавать только запросы, и сервер не может активно передавать информацию клиенту.
При наличии таких сценариев, как спортивные мероприятия, чаты и местоположения в реальном времени, если клиент хочет получить изменения на сервере, он может узнать, есть ли какие-либо новые изменения информации на сервере, только посредством опроса (запроса по времени). .
Эффективность опроса низкая, что приводит к расточительному расходу ресурсов (необходимо постоянно отправлять запросы и поддерживать связь с сервером).
Появление WebSocket позволяет серверу активно отправлять информацию клиенту, позволяя браузеру иметь возможности двусторонней связи в реальном времени.WebSocket
решенная проблема
Супер простой каштан:
создать новыйhtml
файл, запустите этот каштан где-нибудь и попробуйте, вы можете легко начатьWebSocket
:
function socketConnect(url) {
// 客户端与服务器进行连接
let ws = new WebSocket(url); // 返回`WebSocket`对象,赋值给变量ws
// 连接成功回调
ws.onopen = e => {
console.log('连接成功', e)
ws.send('我发送消息给服务端'); // 客户端与服务器端通信
}
// 监听服务器端返回的信息
ws.onmessage = e => {
console.log('服务器端返回:', e.data)
// do something
}
return ws; // 返回websocket对象
}
let wsValue = socketConnect('ws://121.40.165.18:8800'); // websocket对象
вышеперечисленных каштановWebSocket
Адрес интерфейса от:Онлайн тест WebSocket, который также можно использовать для проверки того, доступен ли адрес, заданный серверной частью, во время разработки.
класс веб-сокета:
Когда WebSocket используется во многих местах проекта, лучше инкапсулировать его в класс.
Следующие каштаны были подробно аннотированы, и html-файл также можно использовать напрямую., обычно используется в WebsocketAPI
Все положить это.
Код, прокомментированный ниже, не беспокойтесь об этом, он включает механизм сердцебиения, который используется для поддержания соединения WebSocket.
class WebSocketClass {
/**
* @description: 初始化实例属性,保存参数
* @param {String} url ws的接口
* @param {Function} msgCallback 服务器信息的回调传数据给函数
* @param {String} name 可选值 用于区分ws,用于debugger
*/
constructor(url, msgCallback, name = 'default') {
this.url = url;
this.msgCallback = msgCallback;
this.name = name;
this.ws = null; // websocket对象
this.status = null; // websocket是否关闭
}
/**
* @description: 初始化 连接websocket或重连webSocket时调用
* @param {*} 可选值 要传的数据
*/
connect(data) {
// 新建 WebSocket 实例
this.ws = new WebSocket(this.url);
this.ws.onopen = e => {
// 连接ws成功回调
this.status = 'open';
console.log(`${this.name}连接成功`, e)
// this.heartCheck();
if (data !== undefined) {
// 有要传的数据,就发给后端
return this.ws.send(data);
}
}
// 监听服务器端返回的信息
this.ws.onmessage = e => {
// 把数据传给回调函数,并执行回调
// if (e.data === 'pong') {
// this.pingPong = 'pong'; // 服务器端返回pong,修改pingPong的状态
// }
return this.msgCallback(e.data);
}
// ws关闭回调
this.ws.onclose = e => {
this.closeHandle(e); // 判断是否关闭
}
// ws出错回调
this.onerror = e => {
this.closeHandle(e); // 判断是否关闭
}
}
// heartCheck() {
// // 心跳机制的时间可以自己与后端约定
// this.pingPong = 'ping'; // ws的心跳机制状态值
// this.pingInterval = setInterval(() => {
// if (this.ws.readyState === 1) {
// // 检查ws为链接状态 才可发送
// this.ws.send('ping'); // 客户端发送ping
// }
// }, 10000)
// this.pongInterval = setInterval(() => {
// if (this.pingPong === 'ping') {
// this.closeHandle('pingPong没有改变为pong'); // 没有返回pong 重启webSocket
// }
// // 重置为ping 若下一次 ping 发送失败 或者pong返回失败(pingPong不会改成pong),将重启
// console.log('返回pong')
// this.pingPong = 'ping'
// }, 20000)
// }
// 发送信息给服务器
sendHandle(data) {
console.log(`${this.name}发送消息给服务器:`, data)
return this.ws.send(data);
}
closeHandle(e = 'err') {
// 因为webSocket并不稳定,规定只能手动关闭(调closeMyself方法),否则就重连
if (this.status !== 'close') {
console.log(`${this.name}断开,重连websocket`, e)
// if (this.pingInterval !== undefined && this.pongInterval !== undefined) {
// // 清除定时器
// clearInterval(this.pingInterval);
// clearInterval(this.pongInterval);
// }
this.connect(); // 重连
} else {
console.log(`${this.name}websocket手动关闭`)
}
}
// 手动关闭WebSocket
closeMyself() {
console.log(`关闭${this.name}`)
this.status = 'close';
return this.ws.close();
}
}
function someFn(data) {
console.log('接收服务器消息的回调:', data);
}
// const wsValue = new WebSocketClass('ws://121.40.165.18:8800', someFn, 'wsName'); // 这个链接一天只能发送消息50次
const wsValue = new WebSocketClass('wss://echo.websocket.org', someFn, 'wsName'); // 阮一峰老师教程链接
wsValue.connect('立即与服务器通信'); // 连接服务器
// setTimeout(() => {
// wsValue.sendHandle('传消息给服务器')
// }, 1000);
// setTimeout(() => {
// wsValue.closeMyself(); // 关闭ws
// }, 10000)
Я это прямо в каштаны написал, можно поставитьclass
Поместите его в файл js,export
выйти, а затем использовать его, где вам это нужноimport
Заходите, передайте параметры и можете пользоваться.
Веб-сокет нестабилен
WebSocket не является стабильным.После некоторого периода использования он может быть отключен.Похоже, что нет общественного мнения о том, почему он отключен.Поэтому нам нужно поддерживать подключение WebSocket.Здесь рекомендуются два метода.
WebSocket устанавливает переменную, чтобы определить, закрывать ли соединение вручную:
class
класс используется таким образом: Установить переменную. В обратном вызове сообщения о закрытии/ошибке веб-сокета определить, закрывается ли он вручную. Если нет, переподключиться. Преимущества и недостатки этого способа следующие:
- Преимущества: меньше запросов (относительно соединений Heartbeat), простота настройки.
- Недостатки: Может привести к потере данных В период отключения и повторного подключения обе стороны общаются.
Механизм сердцебиения WebSocket:
Из-за недостатков первого решения, а также могут быть какие-то другие неизвестные обстоятельства, которые приводят к отключению без срабатывания событий Error или Close. Таким образом, фактическое соединение было разорвано, но клиент и сервер не знают об этом и все еще ждут новостей.
Затем умные программисты придумали метод под названиемМеханизм сердцебиенияобходной путь:
Клиент отправляет его каждое фиксированное время, как сердцебиениеping
, чтобы сообщить серверу, что я жив, и сервер вернетpong
, чтобы сообщить клиенту, что сервер жив.
Конкретный метод реализации вышеclass
, откройте его, вы можете увидеть эффект.
О веб-сокете
Боюсь, что в начале будет нагромождено слишком много текстового контента, что вас отпугнет.Теперь, когда все знают, как им пользоваться, давайте вернемся назад и посмотрим на другие точки знаний WebSocket.
Текущее состояние WebSocket:WebSocket.readyState
НижеWebSocket.readyState
Четыре значения (четыре состояния) :
- 0: означает подключение
- 1: Указывает, что соединение установлено успешно и может обмениваться данными.
- 2: указывает, что соединение закрывается.
- 3: указывает, что соединение было закрыто или не удалось открыть соединение.
Мы можем использовать текущее состояние, чтобы делать некоторые вещи, например, в приведенном выше каштане, когда соединение WebSocket успешно, клиенту разрешено отправлятьping
.
if (this.ws.readyState === 1) {
// 检查ws为链接状态 才可发送
this.ws.send('ping'); // 客户端发送ping
}
WebSocket
Также может отправлять/получать двоичные данные
Я и здесь не пробовал, смотрю Учителя Жуань Ифэн.Учебник по веб-сокетамТолько тогда я узнал, что есть такая штука.Если вам интересно, то можете снова зайти в гугл, и все об этом могут знать.
Двоичные данные включают в себя:blob
объект иArraybuffer
объект, поэтому нам нужно иметь дело с ним отдельно.
// 接收数据
ws.onmessage = function(event){
if(event.data instanceof ArrayBuffer){
// 判断 ArrayBuffer 对象
}
if(event.data instanceof Blob){
// 判断 Blob 对象
}
}
// 发送 Blob 对象的例子
let file = document.querySelector('input[type="file"]').files[0];
ws.send(file);
// 发送 ArrayBuffer 对象的例子
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
ws.send(binary.buffer);
Если двоичные данные, которые вы хотите отправить, очень велики, как определить, что передача завершена:
webSocket.bufferedAmount
Атрибут, указывающий, сколько байтов двоичных данных осталось неотправленными:
var data = new ArrayBuffer(10000000);
socket.send(data);
if (socket.bufferedAmount === 0) {
// 发送完毕
} else {
// 发送还没结束
}
Вышеуказанные каштаны принадлежат учителю Жуань Ифэн.Учебник по веб-сокетам
Преимущества веб-сокета:
Наконец, взорвите волну WebSocket:
-
Двусторонняя связь (упомянутый в начале и самый важный момент).
-
Формат данных относительно легкий, небольшие потери производительности, эффективная связь
Заголовок пакета, контролируемый протоколом, меньше, в то время как протокол HTTP должен содержать полный заголовок для каждой связи.
-
лучшая бинарная поддержка
-
Нет ограничений на одно и то же происхождение, клиенты могут связываться с любым сервером
-
Он имеет хорошую совместимость с протоколом HTTP. Порты по умолчанию также 80 и 443, а протокол HTTP используется на этапе рукопожатия, поэтому во время рукопожатия защитить экран непросто, и он может проходить через различные прокси-серверы HTTP.
Эпилог
После прочтения этой статьи, если вы все еще немного запутались, вы должны создать новый html-файл для двух каштанов в статье и запустить его самостоятельно. В противном случае, сколько блогов/туториалов вы прочитаете, будет бесполезно, и вы будете знать правду на практике.Не говорите об этом на бумаге.
Я надеюсь, что друзья, которые прочитали это, могут нажать «Нравится» / «Подписаться», ваша поддержка — самая большая поддержка для меня.
блог,Документы внешнего накопления,Нет публики,GitHub
Выше 2018.10.22
Использованная литература:
Предварительное исследование и реализация повторного подключения пульса веб-сокета