Post on 15-Jul-2015
Szybciej, niż Struś Pędziwiatr
WebSockets w aplikacjach webowych
Krzysztof Rychlicki-Kicior
Jack of all trades @
Ph.D. student & T.A. @ Politechnika Łódzka
Plan prezentacji• Protokół HTTP i jego ograniczenia
• Ramki, Java, AJAX, czyli jak to dawniej bywało
• WebSockets – komunikacyjna magia teraz w Twojej
przeglądarce
• Struś Pędziwiatr czy Wile E. Coyote – porównanie
wydajności
HTTP
• Żądanie + odpowiedź = …i żyli długo i szczęśliwie…
• …ale czy aby na pewno?
• HTTP powstał jako protokół do obsługi powiązanych
ze sobą dokumentów hipertekstowych – obecnie
jest używany w znacznie szerszym kontekście
HTTP – problemy• Jedno połączenie na jeden zasób – rozwiązane (keep
alive)
• Bezstanowość (brak sesji) – rozwiązane (sesje, udostępniane przez popularne frameworki webowe)
• Jednostronność komunikacji – to klient decyduje o komunikacji z serwerem – ?
• Wydajność – protokół HTTP wprowadza spory narzut, który utrudnia komunikację w czasie rzeczywistym – ?
Powrót do przeszłości• Przedstawione ograniczenia są znane od dawna i w
rozmaity sposób próbowano sobie z nimi radzić
• Rozwiązania można podzielić na dwie grupy: natywne i wtyczki
• Do rozwiązań natywnych można zaliczyć iframe, AJAX, rozwiązania typu long-polling
• Najpopularniejsze rozwiązania zewnętrzne opierały się o applety Javy i aplikacje Flashowe
Ramki (iframe)• Jedna z uniwersalnych metod
• Niewidoczna ramka (np. wymiary 0x0) wysyła
żądania cyklicznie lub na zasadzie tzw. forever
frame
AJAX• Tradycyjnie AJAX jest używany do wykonywania
żądań "w tle"
• Dzięki zdarzeniu onreadystatechange, istnieje
możliwość przesyłania cząstkowych odpowiedzi,
podobnie jak w przypadku ramki
• Problem w tym podejściu (podobnie jak forever
frame) wynika z owego braku ograniczeń
Long polling• Rozwiązanie stanowią techniki oparte o long-polling
• Żądanie jest utrzymywane dopóty, dopóki nie
zostaną przesłane dane, jednak z pewnym
czasowym ograniczeniem.
• W razie braku otrzymanych danych, klient ponawia
żądanie
Long polling – AJAX• Nie jest to stricte nowa technika
• Sposób zastosowania AJAX-a zgodnie z założeniami
long pollingu
Long polling – JSONP• AJAX nie może być powszechnie używany do
wywołań międzyserwerowych (cross-domain)
• Możliwość taką daje importowanie skryptów za
pomocą znacznika <script>:
<script src="http://serwer/uzytkownicy/1?callback=odpowiedz"
type="text/javascript"></script>
<script>
function odpowiedz(dane)
{
// skorzystaj z obiektu dane
}
</script>
Long polling – JSONP• Serwer nie zwraca wyłącznie obiektu w formacie
JSON
• Konieczne jest "opakowanie" go w wywołanie
funkcji – w efekcie w kodzie strony jest importowany
następujące wywołanie:
odpowiedz({"ID":1, "Login":"jan12345"});
Rozwiązania zewnętrzne• Java i applety – które królowały w latach 90. –
zapewniały wydajną komunikację za pomocą
gniazd TCP
• Konieczność posiadania Javy
• Dostępność dodatkowych portów
• Odrębna infrastruktura po stronie serwera
Rozwiązania zewnętrzne• Pozostałe wady appletów:
o utrudniona komunikacja z resztą strony internetowej
o niespójny interfejs użytkownika
o certyfikaty, ostrzeżenia, etc…
Rozwiązania zewnętrzne• Z nastaniem nowego wieku popularność zyskała
technologia Adobe Flash
• Zalety i wady podobne, jak w przypadku Javy
• Oprócz klasycznych gniazd TCP, Flash (a dokładnie
Flex) oferuje wsparcie dla wydajnych metod
integracji klientów i serwera (np. BlazeDS)
Nowe koncepcje• Server-sent Events – serwer otrzymuje w pełni
funkcjonalne narzędzie do przesyłania
komunikatów do klientów
• SSE nie są obsługiwane w IE, a ponadto umożliwiają
one jedynie komunikację od serwera do klienta
• WebSockets – pozwalają na dwustronną
komunikację pomiędzy klientem, a serwerem, za
pomocą dedykowanego protokołu
WebSockets• Dwukierunkowy kanał komunikacyjny, który
pozwala na przesyłanie danych z minimalnym
narzutem, w porównaniu do klasycznego protokołu
HTTP
• NIE jest to implementacja klasycznych gniazd TCP
ani UDP, mimo że zasada działania jest podobna
• Nie jest ograniczony tylko do przeglądarki: można
pisać aplikacje desktopowe z wykorzystaniem
zewnętrznych bibliotek, np. Jetty (w Javie)
WebSocketsProcedura nawiązania połączenia WebSockets:
1. Klient wysyła zwykłe żądanie HTTP pod adres URI
spełniający wymagania WebSockets:
2. Żądanie zawiera prośbę o wykonanie tzw.
Upgrade w celu rozpoczęcia komunikacji
dwukierunkowej w trybie full-duplex
3. Komunikacja dwukierunkowa jest prowadzona
niezależnie od innych żądań kierowanych do
serwera
ws://serwer.com/gra
WebSockets• Połączenie WebSocket jest zrywane w momencie
przeładowania lub przejścia do innej strony
• Z tego względu, aplikacje intensywnie
wykorzystujące WS funkcjonują w obrębie jednej
strony
WebSockets• Gniazda webowe pozwalają na transfer danych
tekstowych, jak i binarnych
• Podobnie jak w przypadku protokołu HTTP, tak i
WebSockety potrafią korzystać z protokołu SSL.
Zakładając wsparcie po stronie serwera, w kodzie klienta wystarczy zastosować scheme wss.
WebSockets• Po stronie serwera, WebSockety muszą być
zaimplementowane dodatkowo.
• Wsparcie dla WS jest obecne w licznych
technologiach server-side, takich jak Java EE 7,
ASP.NET czy Node.js
WebSockets• Implementacja po stronie klienta jest trywialna:
var socket = new WebSocket("ws://localhost/czat");
socket.onmessage = function(evt) {
// korzystaj z evt.data
}
socket.send('Hello, World!’);
WebSockets• Również po stronie serwera obsługa nie sprawia
zazwyczaj problemu:
@ServerEndpoint(value="/czat")
public class CzatEndpoint {
@OnMessage
public void handle(String msg, Session ses){
}
// pozostałe adnotacje: @OnOpen, @OnClose,
// @OnError
}
WebSockets• W porównaniu do tradycyjnych gniazd sieciowych,
WebSockety oferują znacznie bardziej przejrzyste
API:
o otwarcie sesji
o zamknięcie sesji
o wysłanie komunikatu
o odebranie komunikatu
o obsługa błędów
Wydajność• Jedną z kluczowych zalet WebSocketów jest ich
wydajność, zwłaszcza w przypadku przesyłania
dużej liczby małych komunikatów
• W takich sytuacjach narzut związany z
wykonywaniem żądań HTTP staje się ogromny
Wydajność• Na potrzeby niniejszej prezentacji wykonałem
proste testy z wykorzystaniem technologii Node.JS i
biblioteki Socket.IO
• Socket.IO pozwala na stosowanie różnych
transportów przezroczyście dla programisty
• Obecnie, Socket.IO udostępnia WebSockety i XHR-
polling
Wydajność• Scenariusz: 500 komunikatów przesyłanych
sekwencyjnie
• Testy były przeprowadzane lokalnie, aby
zlikwidować niepotrzebne opóźnienie
• Wyniki:
o WebSockets – 2542 ms
o XHR-polling – 12431 ms
Praktyczne zastosowania• Narzędzia do komunikacji w czasie rzeczywistym
(czaty, narzędzia do pracy wspólnej – wirtualne
tablice, itd.)
• Gry
• Aplikacje finansowe