Научит вас, как использовать WebSocket вручную [на самом деле, WebSocket не сложно]

внешний интерфейс сервер JavaScript WebSocket
Научит вас, как использовать WebSocket вручную [на самом деле, WebSocket не сложно]

предисловие

Перед этой статьей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:

  1. Двусторонняя связь (упомянутый в начале и самый важный момент).

  2. Формат данных относительно легкий, небольшие потери производительности, эффективная связь

    Заголовок пакета, контролируемый протоколом, меньше, в то время как протокол HTTP должен содержать полный заголовок для каждой связи.

  3. лучшая бинарная поддержка

  4. Нет ограничений на одно и то же происхождение, клиенты могут связываться с любым сервером

  5. Он имеет хорошую совместимость с протоколом HTTP. Порты по умолчанию также 80 и 443, а протокол HTTP используется на этапе рукопожатия, поэтому во время рукопожатия защитить экран непросто, и он может проходить через различные прокси-серверы HTTP.


Эпилог

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

Я надеюсь, что друзья, которые прочитали это, могут нажать «Нравится» / «Подписаться», ваша поддержка — самая большая поддержка для меня.

блог,Документы внешнего накопления,Нет публики,GitHub

Выше 2018.10.22

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

Учебник по веб-сокетам

Предварительное исследование и реализация повторного подключения пульса веб-сокета

Протокол WebSocket: 5 минут от входа до освоения