Socket.io 1.x: używaj tylko WebSockets?

Tworzymy aplikację webową, która będzie działać tylko na nowoczesnych przeglądarkach (IE10+) z różnych powodów.

Jedną z funkcji, które zaimplementowaliśmy, jest Socket.io 1.x. jednak domyślnie Socket.io klient próbuje obsługiwać starsze przeglądarki, więc rozpoczyna połączenie z długim polowaniem, a następnie aktualizuje je do WebSockets. Jest to strata czasu i zasobów, ponieważ wiemy na pewno, że przeglądarka obsługuje WS.

Szukałem i znalazłem tylko tę wiki Strona , która jednak jest o Socket.io 0.9.

W końcu znalazłem dokumentację dla engine. io-client (na której opiera się Socket.io-client 1.X Oddział). To jest kod, który napisałem i wydaje się działać. Jednak chciałbym wiedzieć, czy to prawda, czy robię coś złego: {]}

io.connect('https://...', {
    upgrade: false,
    transports: ['websocket']
})

Co dziwne, samo ustawienie właściwości transports na tablicę z websockets tylko nie wystarczyło; musiałem też wyłączyć upgrade. Czy to zgadza się?

Update

Dokonałem nowych odkryć.

Z {[1] } ustawionym tylko na ['websocket'], nie ma znaczenia czy upgrade jest włączona czy nie. Czy to normalne?

Author: ItalyPaleAle, 2015-01-30

4 answers

Istnieją dwa rodzaje "ulepszeń", które dzieją się z socket.io. pierwszy (w socket.io 1.0+), socket.io uruchamia wszystkie połączenia z żądaniem http i może faktycznie wymieniać niektóre początkowe dane tylko z żądaniem http. Następnie, w pewnym momencie po tym, będzie próbował faktycznie zainicjować połączenie webSocket. połączenie webSocket odbywa się poprzez wysłanie określonego typu żądania http, które określa nagłówek upgrade: websocket, a serwer może następnie odpowiednio odpowiedzieć, czy obsługuje websocket czy nie. Jeśli serwer zgadza się na aktualizację, to dane połączenie http jest "uaktualniane" do protokołu webSocket. W tym momencie klient wie, że webSocket jest obsługiwany i przestaje używać zapytań http, tym samym wypełniając swój upgrade do webSocket.

Możesz całkowicie zapobiec wstępnemu sondażowi http, robiąc to na kliencie:

var socket = io({transports: ['websocket'], upgrade: false});

Zapobiegnie to polubownym połączeniom z twoimi własnymi współpracującymi klientami. Jeśli chcesz zapobiec jakimkolwiek klienci z ever using polling, wtedy możesz dodać to do serwera:

io.set('transports', ['websocket']);

Ale jeśli ustawisz to na serwerze, socket.io klienci, którzy początkowo łączą się z http polling, w ogóle nie będą działać. Tak więc, powinno to być dopasowane tylko z odpowiednimi ustawieniami w kliencie, tak aby klient nigdy nie zaczynał od ankietowania.

To powie obu końcom, że chcesz używać tylko webSockets i socket.io pominie dodatkowe ankiety http na początku. Uczciwe ostrzeżenie, robiąc to wymaga obsługi webSocket, więc wyklucza to kompatybilność ze starszymi wersjami IE, które jeszcze nie obsługiwały webSocket. Jeśli chcesz zachować kompatybilność, po prostu pozwól socket.io zrób to z kilkoma żądaniami http na początku.


Oto więcej informacji na temat aktualizacji protokołu z http do webSocket.

Protokół webSockets inicjuje każdy webSocket połączeniem HTTP. Tak działają wszystkie websockety. To połączenie HTTP zawiera na nim nagłówki, które wskaż, że przeglądarka "chciałaby" uaktualnić się do protokołu webSockets. Jeśli serwer obsługuje ten protokół, to odpowiada, że klient zaktualizuje się do protokołu webSocket i to samo gniazdo przełącza się z protokołu HTTP do protokołu webSocket. Tak ma działać połączenie webSocket. Tak więc fakt, że widzisz połączenie webSocket zaczynające się od połączenia HTTP, jest w 100% normalny.

Możesz skonfigurować socket.io nigdy nie używaj długie sondowanie, jeśli to sprawi, że poczujesz się lepiej, ale nie zmieni to faktu, że połączenie webSocket nadal rozpocznie się od połączenia HTTP, które jest następnie uaktualniane do protokołu webSocket i nie poprawi wydajności działania w nowoczesnych przeglądarkach, które obsługują websocket. Spowoduje to jednak, że połączenie nie będzie działać w starszych przeglądarkach.

 47
Author: jfriend00,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-22 22:42:24

Powiedzieć Socket.IO aby użyć WebSocket tylko zamiast kilku żądań XHR, po prostu dodaj to do serwera węzła:

io.set('transports', ['websocket']);

I na kliencie dodaj to:

var socket = io({transports: ['websocket']});

To mówi Socket.IO używać tylko protokołu WebSocket i nic więcej; jest czystszy, szybszy i zużywa trochę mniej zasobów po stronie klienta i serwera.

Teraz zobaczysz tylko jedno połączenie WebSocket na liście żądań sieciowych, pamiętaj tylko, że IE9 i wcześniejsze nie mogą używać WebSocket.

 23
Author: Nick Steele,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-26 01:32:44

Zamieszczam tę odpowiedź, ponieważ zaakceptowana odpowiedź nie jest poprawna - myli Socket.IO upgrade Z Long-polling AJAX do WebSocket z żądaniem protokołu WSS "Connection: Upgrade". Problem nie polega na tym, że połączenie WebSocket rozpoczyna się jako HTTP i zostaje uaktualnione do WebSocket - jak to nie może? - ale to Socket.IO zaczyna się od długotrwałego połączenia AJAX nawet w przeglądarkach obsługujących WebSocket, a dopiero aktualizuje go później po wymianie ruchu. Bardzo łatwo zobaczyć w narzędzia programistyczne Firefoksa lub Chrome.

Autor pytania ma rację w swoich uwagach. "Upgrade" w Socket.IO nie odnosi się do aktualizacji protokołu HTTP do WSS, jak często jest źle rozumiane, ale do aktualizacji Socket.IO połączenie z połączenia AJAX do WebSocket. Jeśli zaczniesz już z WebSocket (co nie jest domyślne) to upgrade false nie ma żadnego efektu, ponieważ nie musisz uaktualniać. Jeśli zaczniesz od ankietowania i wyłączysz upgrade to zostanie w ten sposób i nie aktualizuje się do WebSocket.

Zobacz odpowiedzi autorstwa Arnolda i Nicka Steele ' a jeśli chcesz uniknąć długich sondaży. Wyjaśnię bardziej szczegółowo, co się dzieje.

To właśnie obserwowałem w moich eksperymentach z prostym WebSocket i Socket.IO aplikacje:

WebSocket

2 zapytań, 1.50 KB, 0.05 s

Z tych 2 żądań:

  1. sama strona HTML
  2. Aktualizacja połączenia do WebSocket

(żądanie aktualizacji połączenia jest widoczne w narzędziach programistycznych z odpowiedzią 101 protokołów przełączania.)

Socket.IO

6 zapytań, 181.56 KB, 0.25 s

Z tych 6 żądań:

  1. sama strona HTML
  2. Socket.IO " s JavaScript (180 kilobajtów)
  3. pierwsza długa ankieta
  4. druga długa ankieta
  5. trzecia długa ankieta
  6. Aktualizacja połączenia do WebSocket

Szczegóły

Wyniki WebSocket, które dostałem na localhost:

Wyniki WebSocket - websocket-vs-socket.io moduł

Socket.IO wyniki, które dostałem na localhost:

Socket.IO wyniki - websocket-vs-socket.io moduł

Sprawdź się

Opublikowałem kod na npm i na GitHub , możesz go uruchomić samodzielnie:

# Install:
npm i -g websocket-vs-socket.io
# Run the server:
websocket-vs-socket.io

I postępuj zgodnie z instrukcjami. Do odinstalowania:

# Uninstall:
npm rm -g websocket-vs-socket.io

Zobacz ta odpowiedź więcej informacji.

 15
Author: rsp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-25 03:21:53

Pomyślałem, że powinienem dodać do zaakceptowanej odpowiedzi powyżej, jakby ktoś chciał wyeliminować Transport ankiet XHR i natychmiast rozpocząć websockets. Poniższy kod jest tylko po to, aby dać wyobrażenie o implementacji:

var url = serverUrl + "/ssClients"  //ssClients is the socket.io namespace

var connectionOptions =  {
    "force new connection" : true,
    "reconnection": true,
    "reconnectionDelay": 2000,                  //starts with 2 secs delay, then 4, 6, 8, until 60 where it stays forever until it reconnects
    "reconnectionDelayMax" : 60000,             //1 minute maximum delay between connections
    "reconnectionAttempts": "Infinity",         //to prevent dead clients, having the user to having to manually reconnect after a server restart.
    "timeout" : 10000,                           //before connect_error and connect_timeout are emitted.
    "transports" : ["websocket"]                //forces the transport to be only websocket. Server needs to be setup as well/
}
var socket = require("socket.io-client")(url, connectionOptions); 

socket.on("connect", function (_socket) {
    logger.info("Client connected to server: " + clientName);
    logger.info("Transport being used: " + socket.io.engine.transport.name);

    socket.emit("join", clientName, function(_socketId) {  //tell the server the client name
        logger.info("Client received acknowledgement from server: " + _socketId);
        logger.info("Transport being used after acknowledgement: " + socket.io.engine.transport.name);

    });
});

Po skonfigurowaniu serwera zobaczysz to:

2015-10-23T19:04:30.076Z - info:    Client connected to server: someClientId 
2015-10-23T19:04:30.077Z - info:    Transport being used: websocket 
2015-10-23T19:04:30.081Z - info:    Client received acknowledgement from server: aMH0SmW8CbiL8w5RAAAA
2015-10-23T19:04:30.081Z - info:    Transport being used after acknowledgement: websocket

Jeśli nie wymusisz transportu, zobaczysz "ankietowanie" zamiast websocket. Nie dzieje się to jednak po stronie klienta, serwer musi być skonfigurowany jako cóż:

var io = require("socket.io")(server, { adapter: adapter, log: false }); //attach io to existing Express (http) server
..
io.set('transports', ['websocket']); //forces client to connect as websockets. If client tries xhr polling, it won't connect.

Danger

Jeśli klient rzeczywiście Nie obsługuje protokół websocket, połączenie nie nastąpi i klient zgłosi xhr poll error.

To działa idealnie dla mnie, ponieważ mogę kontrolować klientów, których mam, więc mam Luksus, aby wymusić websockets od razu, co moim zdaniem jest tym, co zadaje pierwotne pytanie. Mam nadzieję, że to komuś pomoże...

 7
Author: arnold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-23 19:54:03