Web

WebSockets

Komunikacja pełnodupleksowa przez pojedyncze połączenie TCP dla aplikacji webowych.

Poza Modelem Żądanie-Odpowiedź: Potrzeba Komunikacji w Czasie Rzeczywistym

W tradycyjnym modelu HTTP klient wysyła żądanie, a serwer zwraca odpowiedź. W przeglądarce wymiana zwykle zaczyna się od żądania klienta, dlatego aplikacje wymagające odbierania zdarzeń wysyłanych przez serwer korzystały z dodatkowych mechanizmów. Ograniczenie to stało się widoczne wraz z rozwojem aplikacji interaktywnych.

Aplikacje czatu, panele giełdowe, gry wieloosobowe i edytory współdzielonych dokumentów często potrzebują krótkiego czasu dostarczenia zdarzeń. W HTTP/1.1 osiągano to między innymi przez techniki określane jako :

  • Krótkie Odpytywanie (Short Polling): Klient wielokrotnie wysyła żądania do serwera w stałych odstępach czasu, na przykład co 2 sekundy, w celu sprawdzenia, czy pojawiły się nowe dane. Generuje to znaczny ruch sieciowy, gdy większość odpowiedzi jest pusta, i wprowadza opóźnienie.
  • Długie Odpytywanie (Long Polling, Comet): Ulepszenie, w którym klient wysyła żądanie, a serwer utrzymuje połączenie otwarte, dopóki nie będzie miał nowych danych do wysłania. Gdy dane zostaną wysłane, połączenie jest zamykane, a klient natychmiast otwiera nowe. Zmniejsza to liczbę pustych odpowiedzi, ale jest bardziej skomplikowane w implementacji i zużywa zasoby serwera.

Mechanizmy te zwiększały liczbę żądań. W long pollingu klient po każdej odpowiedzi wysyłał następne żądanie. WebSocket zdefiniował standardowy kanał, w którym po ustanowieniu sesji obie strony mogą wysyłać dane.

Czym jest WebSocket? Kanał Dwukierunkowy

umożliwia dwukierunkową sesję komunikacyjną między klientem a serwerem. Po ustanowieniu połączenia obie strony mogą wysyłać dane w dowolnym momencie. Jest to .

W HTTP/1.1 jedno połączenie może obsłużyć wiele żądań, lecz każda wymiana ma semantykę żądania i odpowiedzi. Po handshake klasyczny wariant WebSocket utrzymuje połączenie TCP, w którym klient i serwer wymieniają ramki bez powtarzania nagłówków HTTP dla każdej wiadomości. Zmniejsza to narzut w aplikacjach wymagających częstej wymiany danych.

Uzgadnianie WebSocket: Ulepszanie Połączenia

Handshake WebSocket zaprojektowano z myślą o współpracy z serwerami HTTP i proxy. W klasycznym wariancie rozpoczyna się on jako żądanie HTTP/1.1 i zwykle korzysta z portu 80 albo 443, choć protokół może działać także na innym porcie. Ten proces nazywa się uzgadnianiem WebSocket (handshake). Dla HTTP/2 i HTTP/3 zdefiniowano odrębne mechanizmy uruchamiania WebSocket.

Jak Działa Uzgadnianie

  1. Żądanie Klienta (Uaktualnienie HTTP): Klient (przeglądarka) inicjuje uzgadnianie, wysyłając żądanie HTTP GET do serwera. Żądanie zawiera specjalne nagłówki sygnalizujące zamiar przejścia z HTTP do WebSocket.
    GET /czat HTTP/1.1
    Host: example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Sec-WebSocket-Version: 13

    Kluczowe nagłówki w tym żądaniu to:

    • Connection: Upgrade oraz Upgrade: websocket: Te dwa nagłówki są oficjalnym sygnałem dla serwera, że klient chce zmienić protokół.
    • Sec-WebSocket-Key: Klient wysyła losowo wygenerowaną wartość zakodowaną w Base64. Klucz nie służy do uwierzytelniania. Jest elementem mechanizmu wyzwanie-odpowiedź, który pozwala sprawdzić, czy serwer rozpoznał żądanie WebSocket.
  2. Odpowiedź Serwera (Zmiana Protokołów): Serwer świadomy WebSocket, po otrzymaniu tego żądania o uaktualnienie, przetworzy je i odeśle specjalną odpowiedź HTTP. Jeśli serwer zgadza się na uaktualnienie, odpowie kodem statusu 101 Switching Protocols.
    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

    Kluczowe elementy odpowiedzi to:

    • Kod Statusu 101101: Ten kod potwierdza, że serwer przełącza się z HTTP na protokół wskazany w nagłówku Upgrade.
    • Sec-WebSocket-Accept: Serwer łączy wartość Sec-WebSocket-Key ze stałym identyfikatorem GUID określonym w RFC 6455, oblicza skrót SHA-1 i koduje wynik w Base64. Klient wykonuje tę samą operację i porównuje wynik z odpowiedzią. Nagłówek potwierdza akceptację połączenia przez serwer. Nie zastępuje uwierzytelniania.

Po pomyślnym handshake połączenie przechodzi do przesyłania ramek WebSocket. Klient i serwer mogą od tej chwili wysyłać dane niezależnie od siebie. Komunikaty są przenoszone w jednej lub wielu ramkach, bez nagłówków HTTP dla każdej wiadomości.

Schematy URI WebSocket: ws i wss

Podobnie jak HTTP ma swój własny schemat URI (http://), WebSocket definiuje własne schematy do identyfikacji punktów końcowych WebSocket.

ws:// (WebSocket)
Jest to schemat dla połączeń WebSocket bez TLS. Domyślnie korzysta z portu TCP 80, lecz możliwe jest wskazanie innego portu. Dane mogą być odczytane przez obserwatora sieci, dlatego wrażliwe informacje wymagają ochrony na poziomie transportu.
wss:// (WebSocket Secure)
Jest to schemat połączenia WebSocket chronionego przez TLS, analogiczny do HTTPS. Domyślnie korzysta z portu TCP 443. TLS zapewnia poufność i integralność danych, jeśli certyfikat oraz konfiguracja połączenia są poprawne.
// Nieszyfrowane połączenie WebSocket
ws://czat.example.com/api

// Bezpieczne, szyfrowane połączenie WebSocket
wss://realtime.example.com/gielda

Ramki Danych WebSocket: Protokół Konwersacji

Po uzgadnianiu wszystkie dane są wysyłane w jednostkach zwanych ramkami WebSocket. Jest to lekki protokół ramkowania, zaprojektowany w celu zminimalizowania narzutu. Każda ramka zaczyna się od małego nagłówka, po którym następuje ładunek zawierający dane aplikacji. Nagłówek zawiera metadane dotyczące ładunku.

  • Bit FIN: Flaga wskazująca, czy jest to ostatnia ramka wiadomości. Pozwala to na fragmentację wiadomości na wiele ramek.
  • Opcode: 4-bitowe pole określające typ ramki. Typowe wartości to 0x0 dla kontynuacji, 0x1 dla tekstu, 0x2 dla danych binarnych, 0x8 dla zamknięcia, 0x9 dla ping i 0xA dla pong:
    • continuation: Ramka zawierająca dalszą część pofragmentowanego komunikatu.
    • text: Ładunek to dane tekstowe UTF-8.
    • binary: Ładunek to surowe dane binarne.
    • close: Specjalna ramka kontrolna do zamykania połączenia.
    • ping/pong: Ramki kontrolne używane do sprawdzania aktywności połączenia i wykrywania jego zerwania.
  • Ramki kontrolne: Ramki close, ping i pong nie mogą być fragmentowane, a ich ładunek ma najwyżej 125 bajtów. Odpowiedź pong potwierdza odebranie ping i pozwala sprawdzić aktywność połączenia.
  • Maskowanie: Wszystkie ramki wysyłane od klienta do serwera muszą być maskowane 32-bitowym kluczem. Klient wykonuje operację XOR klucza z ładunkiem, co ogranicza ryzyko zatruwania pamięci podręcznej przez pośredniczące proxy. Klucz znajduje się w nagłówku ramki.
  • Długość i dane ładunku: Nagłówek zawiera również długość ładunku, po której następują same dane ładunku.

Ramkowanie WebSocket ogranicza narzut względem przesyłania pełnych żądań i odpowiedzi HTTP. Minimalny nagłówek niezamaskowanej ramki ma 2 bajty. Ramka klienta zawiera dodatkowo 4-bajtowy klucz maskujący. Pole długości może zawierać wartość od 0 do 125 albo wskazywać dodatkowe 16-bitowe lub 64-bitowe pole długości. Takie ramki są przydatne przy częstej wymianie krótkich komunikatów.

Zastosowania i Aplikacje WebSocket

Dwukierunkowy kanał WebSocket znajduje zastosowanie w aplikacjach, które reagują na zdarzenia przesyłane przez serwer z małym opóźnieniem.

Aplikacje Czatowe

WebSocket obsługuje pokoje czatowe i aplikacje do przesyłania wiadomości. Po wysłaniu wiadomości przez użytkownika serwer może przekazać ją innym połączonym klientom bez odpytywania o aktualizacje.

Wieloosobowe Gry Online

Gry wymagają komunikacji o małym opóźnieniu do synchronizacji pozycji graczy, ich działań i stanu gry. WebSocket może dostarczać dwukierunkowy kanał w aplikacji uruchomionej w przeglądarce.

Transmisje Danych Finansowych na Żywo

Notowania giełdowe, giełdy kryptowalut i pulpity finansowe mogą odbierać aktualizacje cen bez okresowego odpytywania. Serwer może wysyłać nowe dane wielu połączonym klientom.

Współpraca i Edycja w Czasie Rzeczywistym

Aplikacje takie jak Dokumenty Google czy współdzielone edytory kodu mogą używać WebSocket do przesyłania zmian, naciśnięć klawiszy i ruchów kursora uczestnikom sesji.

Powiadomienia w Czasie Rzeczywistym

Po nadejściu wiadomości, wzmianki w mediach społecznościowych albo zakończeniu procesu serwer może wysłać powiadomienie do przeglądarki przez WebSocket. Użytkownik nie musi wtedy odświeżać strony.

Aktualizacje Sportowe na Żywo

Serwisy sportowe mogą przesyłać aktualizacje wyników, komentarz i statystyki w trakcie wydarzenia, uzupełniając przekaz oglądany na drugim ekranie.

Podsumowanie: Protokół dla Aplikacji Interaktywnych

Protokół WebSocket rozszerzył model komunikacji webowej o trwały, pełnodupleksowy kanał dla aplikacji interaktywnych. W klasycznym wariancie wykorzystuje jedno połączenie TCP i ramki o małym narzucie, ograniczając potrzebę okresowego odpytywania serwera.

Uzgadnianie z użyciem HTTP ułatwia współpracę z istniejącymi serwerami i pośrednikami. Po jego zakończeniu serwer może wysyłać zdarzenia bez osobnego żądania dla każdej wiadomości, a klient nadal może inicjować własne komunikaty.

Powiązane artykuły