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
- Żą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: 13Kluczowe nagłówki w tym żądaniu to:
Connection: UpgradeorazUpgrade: 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.
- 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 : 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-Keyze 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/gieldaRamki 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
0x0dla kontynuacji,0x1dla tekstu,0x2dla danych binarnych,0x8dla zamknięcia,0x9dla ping i0xAdla 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.