WebSocket: особенности протокола и пример использования на React

Дмитрий Никульчев, руководитель группы разработки digital-интегратора DD Planet
Источник: Tproger

Интернет — основа сети, техническая инфраструктура, благодаря которой и существует World Wide Web, или Всемирная паутина. По своей сути интернет — гигантская сеть компьютеров, которые могут взаимодействовать друг с другом.

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

Наиболее известные:

  • HTTP (Hyper Text Transfer Protocol) — протокол передачи гипертекста, используется при пересылке веб-страниц между компьютерами;
  • FTP (File Transfer Protocol) — протокол передачи файлов со специального файлового сервера на компьютер пользователя;
  • POP3 (Post Office Protocol) — протокол почтового соединения получения клиентской почты. Серверы POP обрабатывают входящую почту, а протокол POP необходим для обработки запросов на получение почты от пользователей;
  • SMTP (Simple Mail Transfer Protocol) — протокол, который задает набор правил для передачи электронной почты в сети. Сервер SMTP возвращает ответ при отправке;
  • Telnet — протокол удаленного доступа, дает возможность пользователю работать на любой ЭВМ, находящейся с ним в одной сети.

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

Описание

WebSocket обеспечивает обмен данными между браузером и сервером через постоянное соединение. Это двунаправленный, полнодуплексный протокол, который используется в сценарии взаимодействия «Клиент-сервер». Он начинается с ws:// или wss:// в случае безопасного соединения.

Принцип веб-сокета — соединение между клиентом и сервером остается активным до тех пор, пока оно не будет разорвано любой из сторон.

Соединение WebSocket устанавливается посредством HTTP-запроса:

  • клиент, который поддерживает веб-сокеты и хочет установить постоянное соединение, отправляет HTTP-запрос, содержащий набор необходимых заголовков (headers);
  • в ответ он должен получить ответ сервера: HTTP 101 Switching Protocols. Ответ 101 указывает, что сервер переключается на протокол, запрошенный клиентом в заголовке запроса на обновление;
  • клиент получает ответ сервера, и WebSocket-соединение открывается для начала обмена данными.

Особенности протокола

О плюсах WebSocket:

  1. Поддерживает двусторонний обмен данными: может одновременно получать и передавать информацию.
  2. Отправляет данные быстрее, чем HTTP.
  3. Кроссплатформенная совместимость. Для сервера веб-сокета не имеет значения, кто выступает в качестве клиента: веб-сайт или мобильные приложение.
  4. HTTP требует до 2000 байтов накладных расходов, тогда как веб-сокет — всего 2 байта.
  5. Кратковременное отсутствие связи не прерывает соединение. Если интернет будет работать нестабильно, клиенту и серверу не придётся заново устанавливать WebSocket-соединения, они смогут продолжить обмениваться данными в обычном режиме, пока связь не восстановится.
  6. Протокол позволяет работать в асинхронном режиме вместо привычной для веба работы «Запрос-ответ». Так, у клиента и сервера равноправные роли в процессе обмена данными, и они действуют автономно.

О минусах:

  1. Высокие требования к серверному оборудованию.
  2. Молчаливый отвал соединения. При отправке пакета в WebSocket вы не узнаете о том, доставлен ли он или нет, пока не пройдёт время таймаута — по умолчанию 75 секунд. Зачастую приходится вводить дополнительные механизмы общения между клиентом и сервером, чтобы быстро понять, отвечает ли клиент.
  3. Смена сети клиентом. Бывают ситуации, когда клиент находится в дороге и меняется сеть, в которой находится устройство. В таких случаях сервер ничего не знает о смене адреса, если клиент не закрыл соединение при переподключении к другой сети.

Где применяется WebSocket

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

Где используется WebSocket:

  • трейдерские приложения;
  • игровые приложения;
  • чаты;
  • социальные сети;
  • управление IoT.

WebSocket подходит для этих проектов лучше всего, так как в них клиент может не выполнять на своей стороне никаких вычислений, а лишь получать\передавать данные на сервер.

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

Пример из практики

В качестве примера покажу React-component, работающий с веб-сокетом. Его суть проста — отображать текущее состояние соединения и функциональность принудительного закрытия и открытия соединения.

Сервер веб-сокета — ресурс wss://ws.kraken.com/, который с определённой периодичностью отправляет клиентам сообщение о том, что сервер работает.

Использование протокола WebSocket в React-приложении выглядит так:


import React, { useState, useRef, useEffect, useCallback } from "react";

const AppWs = () => {
    const [isPaused, setIsPaused] = useState(false);
    const [data, setData] = useState(null); 
    const [status, setStatus] = useState("");
    const ws = useRef(null);

    useEffect(() => {
        if (!isPaused) {
            ws.current = new WebSocket("wss://ws.kraken.com/"); // создаем ws соединение
            ws.current.onopen = () => setStatus("Соединение открыто");	// callback на ивент открытия соединения
            ws.current.onclose = () => setStatus("Соединение закрыто"); // callback на ивент закрытия соединения

            gettingData();
        }

        return () => ws.current.close(); // кода меняется isPaused - соединение закрывается
    }, [ws, isPaused]);

    const gettingData = useCallback(() => {
        if (!ws.current) return;

        ws.current.onmessage = e => {                //подписка на получение данных по вебсокету
            if (isPaused) return;
            const message = JSON.parse(e.data);
            setData(message);
        };
    }, [isPaused]);

    return (
        <>
            {!!data &&
                <div>
                    <div>
                        <h2>{status}</h2>
                        <p>{`connection ID: ${data?.connectionID}`}</p>
                        <p>{`event: ${data?.event}`}</p>
                        <p>{`status: ${data?.status}`}</p>
                        <p>{`version: ${data?.version}`}</p>
                    </div>
                    <button onClick={() => {
                        ws.current.close();
                        setIsPaused(!isPaused)
                    }}>{!isPaused ? 'Остановить соединение' : 'Открыть соединение' }</button>
                </div>
            }
        </>
    )
}

export default AppWs;

Протокол WebSocket позволяет быстро и безопасно пересылать данные на любой домен, помогает увеличить скорость сайта или приложения. Он поддерживается всеми популярными браузерами: Google Chrome, Apple Safari, Mozilla Firefox, Opera и Internet Explorer, что делает его универсальным.

Найдем решение вашей задачи

Заполнить бриф