web-dev-qa-db-fra.com

Socket.io 1.x: utiliser WebSockets uniquement?

Nous développons une application Web qui ne fonctionnera que sur les navigateurs modernes (IE10 +) pour différentes raisons.

L'une des fonctionnalités que nous avons implémentées est Socket.io 1.x. Cependant, par défaut, le client Socket.io essaie de prendre en charge les anciens navigateurs, il démarre donc une connexion avec une longue interrogation, puis la met à jour vers WebSockets. C'est une perte de temps et de ressources, étant donné que nous savons avec certitude que le navigateur prend en charge WS.

J'ai cherché autour de moi, et je ne peux trouver que cette page wiki qui, cependant, concerne Socket.io 0.9.

Finalement, j'ai trouvé la documentation de engine.io-client (sur laquelle Socket.io-client est basé sur la branche 1.x). C'est le code que j'ai écrit et semble fonctionner. Cependant, je voudrais savoir si c'est correct ou si je fais quelque chose de mal:

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

Bizarrement, il ne suffit pas de définir la propriété transports sur un tableau avec websockets; J'ai également dû désactiver upgrade. Est-ce correct?

Mise à jour

J'ai fait de nouvelles découvertes.

Avec transports réglé sur ['websocket'] uniquement, cela ne fait aucune différence que upgrade soit activé ou non. Est-ce normal?

36
ItalyPaleAle

Il existe deux types de "mises à niveau" avec socket.io. Tout d'abord (dans socket.io 1.0+), socket.io démarre toutes les connexions avec une requête d'interrogation http et il peut en fait échanger certaines données initiales avec juste une requête http. Ensuite, à un moment donné, il essaiera d'initier une connexion webSocket. la connexion webSocket se fait en envoyant un type particulier de requête http qui spécifie un upgrade: websocket header et le serveur peut alors répondre de manière appropriée, qu'il prenne en charge websocket ou non. Si le serveur accepte la mise à niveau, cette connexion http particulière est alors "mise à niveau" vers le protocole webSocket. À ce stade, le client sait alors que webSocket est pris en charge et il cesse d'utiliser les requêtes http d'interrogation, complétant ainsi son upgrade à webSocket.

Vous pouvez empêcher entièrement l'interrogation http initiale en procédant ainsi sur le client:

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

Cela empêchera d'interroger les connexions de vos propres clients coopérants. Si vous souhaitez empêcher des clients d'utiliser le polling, vous pouvez l'ajouter au serveur:

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

Mais, si vous le définissez sur le serveur, les clients socket.io qui se connectent initialement avec l'interrogation http ne fonctionneront pas du tout. Par conséquent, cela ne doit être mis en correspondance qu'avec les bons paramètres dans le client de sorte que le client ne commence jamais par l'interrogation.

Cela indiquera aux deux extrémités que vous ne souhaitez utiliser que webSockets et socket.io ignorera l'interrogation http supplémentaire au début. Juste avertissement, cela nécessite la prise en charge de webSocket, ce qui exclut la compatibilité avec les anciennes versions de IE qui ne prenaient pas encore en charge webSocket. Si vous souhaitez conserver la compatibilité, laissez simplement socket.io le faire chose avec quelques requêtes http au départ.


Voici plus d'informations sur la mise à niveau du protocole de http vers webSocket.

Le protocole webSockets lance CHAQUE webSocket avec une connexion HTTP. C'est ainsi que fonctionnent tous les webSockets. Cette connexion HTTP contient des en-têtes qui indiquent que le navigateur "aimerait" passer au protocole webSockets. Si le serveur prend en charge ce protocole, il répond en disant au client qu'il va mettre à niveau vers le protocole webSocket et que ce socket passe alors du protocole HTTP au protocole webSocket. Voici comment une connexion webSocket est conçue pour fonctionner. Ainsi, le fait que vous voyez votre connexion webSocket commençant par une connexion HTTP est 100% normal.

Vous pouvez configurer socket.io pour NE JAMAIS utiliser d'interrogation longue si cela vous fait vous sentir mieux, mais cela ne changera pas le fait que la connexion webSocket commencera toujours avec une connexion HTTP qui est ensuite mise à niveau vers le protocole webSocket et cela n'améliorera pas la efficacité de fonctionnement dans les navigateurs modernes qui prennent en charge les webSockets. Cependant, cela fera en sorte que votre connexion ne fonctionne pas dans les anciens navigateurs.

55
jfriend00

Pour dire à Socket.IO d'utiliser WebSocket uniquement au lieu de quelques requêtes XHR, ajoutez simplement ceci au serveur Node:

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

Et sur le client, ajoutez ceci:

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

Cela indique à Socket.IO de n'utiliser que le protocole WebSocket et rien d'autre; il est plus propre, plus rapide et utilise un peu moins de ressources côté client et côté serveur.

Maintenant, vous ne verrez qu'une seule connexion WebSocket dans votre liste de demandes réseau, gardez simplement à l'esprit qu'IE9 et les versions antérieures ne peuvent pas utiliser WebSocket.

29
Nick Steele

Je poste cette réponse car la réponse acceptée n'est pas correcte - cela confond la mise à niveau Socket.IO de l'interrogation longue AJAX vers WebSocket avec la requête "Connexion: mise à niveau" du protocole WSS. Le problème n'est pas que la connexion WebSocket démarre en tant que HTTP et soit mise à niveau vers WebSocket - comment ne pourrait-elle pas? - mais que Socket.IO commence par une longue interrogation AJAX même sur les navigateurs prenant en charge WebSocket, et ne le met à niveau que plus tard après avoir échangé du trafic. Il est très facile à voir dans les outils de développement de Firefox ou Chrome.

L'auteur de la question a raison dans ses observations. La "mise à niveau" dans Socket.IO ne fait pas référence à la mise à niveau du protocole HTTP vers WSS car elle est souvent mal comprise, mais à la mise à niveau de la connexion Socket.IO à partir d'une interrogation longue AJAX à WebSocket. Si vous commencez déjà avec WebSocket (ce qui n'est pas la valeur par défaut), la mise à niveau false n'a aucun effet car vous n'avez pas besoin de la mettre à niveau. Si vous commencez par l'interrogation et désactivez la mise à niveau, cela reste ainsi et ne passe pas à WebSocket.

Voir les réponses de arnold et Nick Steele si vous voulez éviter de commencer par long-polling. Je vais expliquer ce qui se passe plus en détail.

C'est ce que j'ai observé dans mes expériences avec des applications WebSocket et Socket.IO simples:

WebSocket

2 requêtes, 1.50 KB, 0.05 s

De ces 2 demandes:

  1. Page HTML elle-même
  2. mise à niveau de la connexion à WebSocket

(La demande de mise à niveau de connexion est visible sur les outils de développement avec une réponse 101 Switching Protocols.)

Socket.IO

6 requêtes, 181.56 KB, 0.25 s

De ces 6 demandes:

  1. la page HTML elle-même
  2. JavaScript de Socket.IO (180 kilo-octets)
  3. première longue interrogation AJAX
  4. deuxième interrogation longue AJAX
  5. troisième interrogation longue AJAX
  6. mise à niveau de connexion à WebSocket

Détails

Résultats WebSocket que j'ai obtenus sur localhost:

WebSocket results - websocket-vs-socket.io module

Résultats Socket.IO que j'ai obtenus sur localhost:

Socket.IO results - websocket-vs-socket.io module

Testez-vous

J'ai publié le code sur npm et sur GitHub , vous pouvez l'exécuter vous-même:

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

et suivez les instrictions. Pour désinstaller:

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

Voir cette réponse pour plus d'informations.

21
rsp

J'ai pensé que je devrais ajouter à la réponse acceptée ci-dessus, comme si quelqu'un voulait éliminer le transport d'interrogation XHR et lancer immédiatement des websockets. Le code ci-dessous est juste pour donner une idée de l'implémentation:

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);

    });
});

Une fois le serveur configuré, vous verrez ceci:

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

Si vous ne forcez pas le transport, vous verrez "polling" au lieu de websocket. Cependant, cela ne se produit pas uniquement côté client, le serveur doit également être configuré:

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

Si le client ne prend pas en charge le protocole websocket, aucune connexion ne se produit et le client signale un xhr poll error.

Cela fonctionne parfaitement pour moi parce que je peux contrôler les clients que j'ai, j'ai donc le luxe de forcer les websockets immédiatement, ce qui, je crois, est ce que la question initiale pose. J'espère que cela aide quelqu'un là-bas ...

8
arnold