WebSockets - komunikacja z serwerem
Sieć WWW została w dużej mierze zbudowana wokół paradygmatu żądanie / odpowiedź protokołu HTTP. Klient ładuje stronę internetową i nic się nie dzieje, dopóki użytkownik nie kliknie następnej strony. Około 2005 roku AJAX zaczął sprawiać, że internet był bardziej dynamiczny. Mimo to cała komunikacja HTTP jest sterowana przez klienta, co wymaga interakcji użytkownika lub okresowego odpytywania w celu załadowania nowych danych z serwera.
Technologie umożliwiające serwerowi wysyłanie danych do klienta w momencie, gdy wie, że są dostępne nowe dane, istnieją już od jakiegoś czasu. Noszą imiona takie jak"Push" lub “Comet”.
Z long polling, klient otwiera połączenie HTTP z serwerem, który utrzymuje je otwarte do czasu wysłania odpowiedzi. Gdy serwer faktycznie ma nowe dane, wysyła odpowiedź. Długie odpytywanie i inne techniki działają całkiem dobrze. Jednak wszystkie z nich mają wspólny problem, przenoszą narzut HTTP, co nie czyni ich dobrze dostosowanymi do aplikacji o małych opóźnieniach. Na przykład strzelanka dla wielu graczy w przeglądarce lub dowolna inna gra online ze składnikiem czasu rzeczywistego.
Przenoszenie gniazd do sieci
Specyfikacja Web Socket definiuje API ustanawiające połączenia „gniazdowe” między przeglądarką internetową a serwerem. Mówiąc prościej, istnieje trwałe połączenie między klientem a serwerem i obie strony mogą rozpocząć wysyłanie danych w dowolnym momencie.
Połączenie z gniazdem internetowym można po prostu otworzyć za pomocą konstruktora -
var connection = new WebSocket('ws://html5rocks.websocket.org/echo', ['soap', 'xmpp']);
wsto nowy schemat adresu URL dla połączeń WebSocket. Jest równieżwssdla bezpiecznego połączenia WebSocket w ten sam sposób https jest używany do bezpiecznych połączeń HTTP.
Dołączenie niektórych programów obsługi zdarzeń natychmiast do połączenia pozwala wiedzieć, kiedy połączenie jest otwierane, otrzymywane komunikaty przychodzące lub wystąpił błąd.
Drugi argument akceptuje opcjonalne subprotocols. Może to być ciąg lub tablica ciągów. Każdy ciąg powinien reprezentowaćsubprotocol nazwa i serwer akceptuje tylko jeden z przekazanych subprotocolsw tablicy. Przyjętysubprotocol można określić, uzyskując dostęp do właściwości protokołu obiektu WebSocket.
// When the connection is open, send some data to the server
connection.onopen = function () {
connection.send('Ping'); // Send the message 'Ping' to the server
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
};
Komunikacja z serwerem
Gdy tylko uzyskamy połączenie z serwerem (gdy uruchomione zostanie zdarzenie open) możemy rozpocząć wysyłanie danych do serwera metodą send (your message) na obiekcie połączenia. Kiedyś obsługiwał tylko ciągi znaków, ale w najnowszej specyfikacji może teraz również wysyłać wiadomości binarne. Do wysyłania danych binarnych służy obiekt Blob lub ArrayBuffer.
// Sending String
connection.send('your message');
// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {
binary[i] = img.data[i];
}
connection.send(binary.buffer);
// Sending file as Blob
var file = document.querySelector('input[type = "file"]').files[0];
connection.send(file);
Serwer może również wysyłać nam wiadomości w dowolnym momencie. Ilekroć tak się dzieje, następuje wywołanie zwrotne onmessage. Wywołanie zwrotne odbiera obiekt zdarzenia, a właściwy komunikat jest dostępny za pośrednictwem data
właściwości.
WebSocket może również odbierać wiadomości binarne w najnowszej specyfikacji. Ramki binarne można odbierać w formacie Blob lub ArrayBuffer. Aby określić format otrzymanego pliku binarnego, ustaw właściwość binaryType obiektu WebSocket na „blob” lub „arraybuffer”. Domyślnym formatem jest „blob”.
// Setting binaryType to accept received binary as either 'blob' or 'arraybuffer'
connection.binaryType = 'arraybuffer';
connection.onmessage = function(e) {
console.log(e.data.byteLength); // ArrayBuffer object if binary
};
Kolejną nowo dodaną funkcją WebSocket są rozszerzenia. Korzystając z rozszerzeń, będzie można wysyłać ramki skompresowane, zmultipleksowane itp.
// Determining accepted extensions
console.log(connection.extensions);
Komunikacja między źródłami
Będąc nowoczesnym protokołem, komunikacja między źródłami jest wbudowana bezpośrednio w WebSocket. WebSocket umożliwia komunikację między stronami w dowolnej domenie. Serwer decyduje, czy udostępnić swoją usługę wszystkim klientom, czy tylko tym, którzy znajdują się w zestawie dobrze zdefiniowanych domen.
Serwery proxy
Każda nowa technologia wiąże się z nowym zestawem problemów. W przypadku WebSocket jest to kompatybilność z serwerami proxy, które pośredniczą w połączeniach HTTP w większości sieci firmowych. Protokół WebSocket wykorzystuje system aktualizacji HTTP (który jest normalnie używany dla HTTP / SSL) do „aktualizacji” połączenia HTTP do połączenia WebSocket. Niektóre serwery proxy nie lubią tego i przerywają połączenie. Dlatego nawet jeśli dany klient korzysta z protokołu WebSocket, nawiązanie połączenia może być niemożliwe. To sprawia, że kolejna sekcja jest jeszcze ważniejsza :)
Strona serwera
Korzystanie z protokołu WebSocket tworzy zupełnie nowy wzorzec użycia dla aplikacji po stronie serwera. Podczas gdy tradycyjne stosy serwerów, takie jak LAMP, są zaprojektowane w oparciu o cykl żądanie / odpowiedź HTTP, często nie radzą sobie dobrze z dużą liczbą otwartych połączeń WebSocket. Utrzymanie dużej liczby otwartych połączeń w tym samym czasie wymaga architektury, która zapewnia wysoką współbieżność przy niskim koszcie wydajności.