ProIT: медіа для профі в IT
5 хв

WebSockets: навіщо потрібні та як з ними працювати

author avatar Вікторія Єленська
Python Web Developer в NIX

Сьогодні незамінними для нас стали застосунки, які дають змогу миттєво обмінюватися повідомленнями та слідкувати за новинами онлайн. Вебсокети — один з інструментів, що дозволяє розробникам реалізувати такі додатки.

Що таке вебсокети

WebSocket — це двонаправлений повнодуплексний протокол зв’язку між клієнтом та сервером. Що це значить? На відміну від HTTP-протоколу, який працює за принципом «‎‎запит від клієнта — відповідь від сервера», у вебсокетах і сервер, і клієнт можуть надсилати один одному повідомлення. Кожна сторона комунікації здатна одночасно отримувати та відправляти дані.


У вебсокетах обмін повідомленнями проходить через єдиний канал зв’язку. Він залишається відкритим протягом усієї комунікації, а за необхідності будь-яка зі сторін може його закрити.

Відмінності від HTTP-протоколу

HTTP

WebSocket

Однонаправлений протокол: тільки клієнт може ініціювати комунікацію — відправляти запити, сервер може тільки відповідати

Двонаправлений протокол: після встановлення з’єднання будь-яка сторона може відправляти повідомлення

З’єднання нетривале, за замовчуванням закривається після відповіді сервера

З’єднання підтримується до завершення комунікації

Під час комунікації завжди витрачається час на запит клієнта, навіть якщо важлива тільки відповідь сервера

Сервер може відправити повідомлення, не чекаючи на запит клієнта

Обов’язкове використання хедерів у повідомленнях

Після встановлення з’єднання у хедерах немає потреби, що значно зменшує розмір кожного повідомлення

Підтримує кешування автоматично

За замовчуванням не підтримує кешування

Структура WebSocket протоколу

Вебсокет протокол існує як надбудова TCP. Специфікація визначає дві URI схеми для вебсокетів: ws:// для нешифрованого з’єднання та wss:// відповідно — для шифрованого. Протокол складається з початкового хендшейку і безпосередньо обміну даними.

Handshake

У код-блоці нижче можете поглянути, як виглядає handshake з боку клієнта. Тут присутній header Connection: Upgrade. Також видно, який саме upgrade пропонується, — Upgrade: websocket:

Сервер підтверджує handshake статус кодом 101 — зміна протоколу, і так само надсилає деталі про новий connection:

Обмін даними

Дані надсилаються у вигляді фреймів із заданим типом. Кожне повідомлення може складатися з одного чи більше фреймів. Усі вони повинні бути однакового типу. Такими типами можуть бути текст, бінарні дані та контрол фрейми, призначені не для передачі даних, а для службових сигналів на рівні протоколу. Наприклад, що з’єднання потрібно закрити.

Socket.IO

Це один з найпопулярніших інструментів для роботи з вебсокет протоколом. Він складається з вебсокет сервера та клієнтської бібліотеки. Спершу вони були реалізовані на JavaScript, але згодом з’явилися реалізації на багатьох інших мовах програмування. Socket.IO реалізує додатковий функціонал, якого немає у чистому WebSocket. Наприклад, автоматичні перепідключення, якщо з’єднання втрачене; або fallback до HTTP long polling, якщо WebSocket протокол не підтримується; а також впровадження неймспейсів і кімнат.

Namespaces

Необхідні для розділення відповідальності (separation of concerns) у межах одного застосунку. Socket.IO дозволяє створювати декілька неймспейсів, які поводитимуться як окремі канали комунікації. Водночас під капотом вони будуть використовувати одне й те саме з’єднання. Розділяти на неймспейси може бути логічно за модулями у програмі або, наприклад, за спільними пермішенами.

Кімнати

Це другий рівень ієрархії. У кожному неймспейсі, у тому числі дефолтному, можна створювати окремі канали — так звані кімнати, до яких клієнти можуть долучатися та виходити з них. Таким чином, ви можете транслювати повідомлення у «‎‎кімнату», і його отримають всі клієнти, котрі приєдналися до неї. Це може бути зручно для того, щоб одночасно відправити повідомлення групі користувачів або зібрати повідомлення з декількох девайсів для одного юзера.

Альтернативи сокетам

HTTP Polling

Якщо нам постійно потрібно слідкувати за оновленням інформації на сервері, в деяких випадках це можна реалізувати за допомогою HTTP-протоколу — у вигляді HTTP Рolling.

Існує декілька видів HTTP Polling:

  • short polling — простий підхід, однак вважається поганою практикою. Клієнт постійно перепитує сервер, чи готова запитувана інформація. Сервер обробляє реквести щойно вони надходять і відповідає пустим респонсом, якщо дані не готові. В такому випадку велика кількість реквестів перевантажує сервер.
  • long polling — клієнт надсилає один реквест на сервер і очікує відповіді. Сервер своєю чергою затримує реквест, допоки потрібні дані не стануть доступними чи у реквеста не закінчиться заданий таймаут. За оптимальних умов ми отримуємо відповідь щойно на сервері змінюються дані й не створюємо так багато трафіку, як при short polling. Однак на практиці доволі складно налаштувати відправку реквестів так, щоб вони не були ні занадто частими (і в більшості випадків не отримували відповіді), ні занадто повільними, тобто довго затримувались на сервері й марно витрачали ресурси.

У результаті HTTP polling — не дуже зручний підхід, якщо нам вкрай важливо отримувати інформацію в реальному часі.

HTTP Streaming & Server-sent events

Гарний варіант для subscribe-only випадків. Наприклад, для підписки на оновлення стрічки новин чи надсилання сповіщень у браузер. Клієнт робить один HTTP-реквест, встановлюючи з’єднання, а сервер відповідає серією респонсів у міру того, як у нього з’являються відповідні дані. Респонси відправлятимуться, допоки клієнт не закриє з’єднання. Таким чином, зникає необхідність відкривати й закривати з’єднання для кожної пари реквест-респонс.

Недоліки такого підходу:

  • Не гарантує миттєвої доставки повідомлень: з’єднання може бути перерване, реквест може потрапити в чергу інших HTTP-реквестів.
  • Клієнт не може відправляти дані на сервер, що унеможливлює використання цього підходу в застосунках, які потребують справжньої інтерактивності. Тобто там, де клієнт і сервер можуть надсилати один одному дані без додаткових проміжних запитів.

Застосування вебсокетів

Оскільки вебсокети підтримують двонаправлений зв’язок, вони ідеально підходять для ситуацій, коли потрібен швидкий двосторонній обмін даними. Це онлайн-ігри, чати, фінансові застосунки, новини, обмін даними з IoT-девайсами.

Не варто використовувати вебсокети, якщо немає потреби в інтерактивності, немає постійного двостороннього трафіку, а натомість — є високі вимоги щодо безпеки. Адже довготривале відкрите з’єднання додає чимало ризиків.

Security

Як будь-яка комунікація в мережі, комунікація по вебсокет протоколу має певні вразливості.

Виділяють такі можливі напрями атак:

  • XSS (cross site scripting), SQL-ін’єкції — впровадження шкідливого коду у повідомлення.
  • Man-in-the-middle — перехоплення інформації з каналу зв’язку.
  • DoS (Denial of Service) — відправка великої кількості запитів, аби зробити ресурс недоступним користувачам.
  • Неавторизований доступ до інформації.

Як захиститися:

  • Валідувати дані.
  • Використовувати шифроване з’єднання — wss://.
  • Впровадити rate limiting — обмеження по кількості повідомлень за одиницю часу.
  • Додати аутентифікацію на етапі хендшейку. Один із варіантів — використовувати ticket-based аутентифікацію. Це коли клієнт перед апгрейдом з’єднання контактує із HTTP-сервером, який генерує ticket з необхідною інформацією про юзера. Далі клієнт надсилає цей ticket WebSocket-серверу, котрий валідує його і тільки потім надає згоду на з’єднання.

Вебсокети в Python

Серед бібліотек, які існують у Python та активно розвиваються, можна згадати такі:

  1. python-socketio — фреймворк-незалежна імплементація Socket.IO для Python, має синхронний та асинхронний варіанти;
  2. Flask-SocketIO — інтеграція Socket.IO та Flask;
  3. Django Channels — розширення для Django-фреймворку, додає підтримку вебсокет протоколу, HTTP long polling, MQTT; дозволяє обрати між синхронним та асинхронним варіантом імплементації;
  4. Autobahn|Python — реалізація вебсокет протоколу і WAMP (web application messaging protocol) на Twisted та asyncio;
  5. websockets — бібліотека для створення вебсокет серверів і клієнтів на основі вебсокет протоколу. Дефолтна імплементація побудована на asyncio, але дає змогу використовувати threading за бажанням;
  6. websocket-client — низькорівневий вебсокет клієнт для Python на основі чистого вебсокет протоколу.

WebSocket протокол дає можливість створювати інтерактивну комунікацію між клієнтом і сервером без необхідності постійно пінгувати сервер. Таким чином ми економимо час, прискорюємо роботу застосунку і можемо підтягувати зміни в режимі реального часу.
Як і з будь-якою технологією, вебсокети незамінні там, де вони доречні, але їх застосування не завжди потрібне. Часом воно несе додаткові ризики й потребує окремих знань для правильного, безпечного застосування.

Приєднатися до company logo
Продовжуючи, ти погоджуєшся з умовами Публічної оферти та Політикою конфіденційності.