Versione npmBuildWindows x86 BuildStato di copertura

ws è un semplice da usare, incredibilmente veloce e accuratamente testata per l’implementazione di client e server WebSocket.

Passa la suite di test abbastanza estesa di Autobahn: server, client.

Nota: Questo modulo non funziona nel browser. Il client nei documenti è un riferimento ad un back end con il ruolo di un client nella comunicazione WebSocket. I client del browser devono usare l’oggetto nativoWebSocket. Per far funzionare lo stesso codice senza soluzione di continuità su Node.js e sul browser, si può usare uno dei molti wrapper disponibili su npm, comeisomorphic-ws.

Indice

  • Supporto al protocollo
  • Installazione
    • Opt-per prestazioni e conformità alle specifiche
  • Documenti API
  • Compressione WebSocket
  • Esempi di utilizzo
    • Invio e ricezione di dati testuali
    • Invio di dati binari dati binari
    • Semplice server
    • Server HTTP/S esterno
    • Server multipli che condividono un singolo server HTTP/S
    • Autenticazione del client
    • Server broadcast
    • echo.websocket.org demo
    • Utilizzare la Node.js streams API
    • Altri esempi
  • FAQ
    • Come ottenere l’indirizzo IP del client?
    • Come rilevare e chiudere le connessioni interrotte?
    • Come connettersi tramite un proxy?
  • Changelog
  • Licenza

Protocollo supportato

  • HyBi drafts 07-12 (Usare l’opzione protocolVersion: 8)
  • HyBi drafts 13-17 (Attuale default, in alternativa opzioneprotocolVersion: 13)

Installazione

npm install ws

Opt-in per prestazioni e conformità alle specifiche

Ci sono 2 moduli opzionali che possono essere installati insieme al wsmodule. Questi moduli sono addon binari che migliorano certe operazioni; sono disponibili binari precostituiti per le piattaforme più popolari, quindi non è necessario avere un compilatore C++ installato sulla propria macchina.

  • npm install --save-optional bufferutil: Permette di eseguire in modo efficiente operazioni come il mascheramento e lo smascheramento del carico utile dei dati dei WebSocketframes.
  • npm install --save-optional utf-8-validate: Permette di controllare in modo efficiente se un messaggio contiene UTF-8 valido come richiesto dalla specifica.

Documenti API

Vedi /doc/ws.md per la documentazione simile a quella di Node.js delle classi ws e delle funzioni di utilità.

Compressione WebSocket

ws supporta l’estensione permessage-deflate che permette al client e al server di negoziare un algoritmo di compressione e i suoi parametri, e poi applicarlo selettivamente ai carichi di dati di ogni messaggio WebSocket.

L’estensione è disabilitata per default sul server e abilitata per default sul client. Aggiunge un overhead significativo in termini di prestazioni e consumo di memoria, quindi suggeriamo di abilitarla solo se è veramente necessaria.

Nota che Node.js ha una serie di problemi con la compressione ad alte prestazioni, dove una maggiore concorrenza, specialmente su Linux, può portare a una frammentazione catastrofica della memoria e a prestazioni lente. Se intendete usare permessage-deflate in produzione, vale la pena impostare un test rappresentativo del vostro carico di lavoro e assicurarsi che Node.js/zlib lo gestisca con prestazioni e utilizzo della memoria inaccettabili.

Tuning di permessage-deflate può essere fatto tramite le opzioni definite di seguito. Puoi anche usare zlibDeflateOptions e zlibInflateOptions, che viene passato direttamente nella creazione dei flussi grezzi deflate/inflate.

Vedi la documentazione per altre opzioni.

const WebSocket = require('ws');const wss = new WebSocket.Server({ port: 8080, perMessageDeflate: { zlibDeflateOptions: { // See zlib defaults. chunkSize: 1024, memLevel: 7, level: 3 }, zlibInflateOptions: { chunkSize: 10 * 1024 }, // Other options settable: clientNoContextTakeover: true, // Defaults to negotiated value. serverNoContextTakeover: true, // Defaults to negotiated value. serverMaxWindowBits: 10, // Defaults to negotiated value. // Below options specified as default values. concurrencyLimit: 10, // Limits zlib concurrency for perf. threshold: 1024 // Size (in bytes) below which messages // should not be compressed. }});

Il client userà l’estensione solo se è supportata e abilitata sul server. Per disabilitare sempre l’estensione sul client impostare l’opzioneperMessageDeflate su false.

const WebSocket = require('ws');const ws = new WebSocket('ws://www.host.com/path', { perMessageDeflate: false});

Esempi di utilizzo

Invio e ricezione di dati testuali

const WebSocket = require('ws');const ws = new WebSocket('ws://www.host.com/path');ws.on('open', function open() { ws.send('something');});ws.on('message', function incoming(data) { console.log(data);});

Invio di dati binari

const WebSocket = require('ws');const ws = new WebSocket('ws://www.host.com/path');ws.on('open', function open() { const array = new Float32Array(5); for (var i = 0; i < array.length; ++i) { array = i / 2; } ws.send(array);});

Server semplice

const WebSocket = require('ws');const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', function connection(ws) { ws.on('message', function incoming(message) { console.log('received: %s', message); }); ws.send('something');});

Esterno HTTP/S server

const fs = require('fs');const https = require('https');const WebSocket = require('ws');const server = https.createServer({ cert: fs.readFileSync('/path/to/cert.pem'), key: fs.readFileSync('/path/to/key.pem')});const wss = new WebSocket.Server({ server });wss.on('connection', function connection(ws) { ws.on('message', function incoming(message) { console.log('received: %s', message); }); ws.send('something');});server.listen(8080);

Più server che condividono un singolo server HTTP/S

const http = require('http');const WebSocket = require('ws');const url = require('url');const server = http.createServer();const wss1 = new WebSocket.Server({ noServer: true });const wss2 = new WebSocket.Server({ noServer: true });wss1.on('connection', function connection(ws) { // ...});wss2.on('connection', function connection(ws) { // ...});server.on('upgrade', function upgrade(request, socket, head) { const pathname = url.parse(request.url).pathname; if (pathname === '/foo') { wss1.handleUpgrade(request, socket, head, function done(ws) { wss1.emit('connection', ws, request); }); } else if (pathname === '/bar') { wss2.handleUpgrade(request, socket, head, function done(ws) { wss2.emit('connection', ws, request); }); } else { socket.destroy(); }});server.listen(8080);

Autenticazione del client

const http = require('http');const WebSocket = require('ws');const server = http.createServer();const wss = new WebSocket.Server({ noServer: true });wss.on('connection', function connection(ws, request, client) { ws.on('message', function message(msg) { console.log(`Received message ${msg} from user ${client}`); });});server.on('upgrade', function upgrade(request, socket, head) { // This function is not defined on purpose. Implement it with your own logic. authenticate(request, (err, client) => { if (err || !client) { socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n'); socket.destroy(); return; } wss.handleUpgrade(request, socket, head, function done(ws) { wss.emit('connection', ws, request, client); }); });});server.listen(8080);

Vedi anche l’esempio fornito usando express-session.

Server broadcast

Un WebSocket client che trasmette a tutti i client WebSocket collegati, incluso se stesso.

const WebSocket = require('ws');const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', function connection(ws) { ws.on('message', function incoming(data) { wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { client.send(data); } }); });});

Un WebSocket client che trasmette ad ogni altro client WebSocket collegato, escluso se stesso.

const WebSocket = require('ws');const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', function connection(ws) { ws.on('message', function incoming(data) { wss.clients.forEach(function each(client) { if (client !== ws && client.readyState === WebSocket.OPEN) { client.send(data); } }); });});

demo di echo.websocket.org

const WebSocket = require('ws');const ws = new WebSocket('wss://echo.websocket.org/', { origin: 'https://websocket.org'});ws.on('open', function open() { console.log('connected'); ws.send(Date.now());});ws.on('close', function close() { console.log('disconnected');});ws.on('message', function incoming(data) { console.log(`Roundtrip time: ${Date.now() - data} ms`); setTimeout(function timeout() { ws.send(Date.now()); }, 500);});

Usa la Node.js streams API

const WebSocket = require('ws');const ws = new WebSocket('wss://echo.websocket.org/', { origin: 'https://websocket.org'});const duplex = WebSocket.createWebSocketStream(ws, { encoding: 'utf8' });duplex.pipe(process.stdout);process.stdin.pipe(duplex);

Altri esempi

Per un esempio completo con un client browser che comunica con un server ws, vedere la cartellaexamples.

Altrimenti, vedere i casi di test.

FAQ

Come ottenere l’indirizzo IP del client?

L’indirizzo IP remoto può essere ottenuto dal socket grezzo.

const WebSocket = require('ws');const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', function connection(ws, req) { const ip = req.socket.remoteAddress;});

Quando il server gira dietro un proxy come NGINX, lo standard de-facto è usare l’intestazione X-Forwarded-For.

wss.on('connection', function connection(ws, req) { const ip = req.headers.split(/\s*,\s*/);});

Come rilevare e chiudere le connessioni interrotte?

A volte il collegamento tra il server e il client può essere interrotto in un modo che mantiene sia il server che il client all’oscuro dello stato interrotto della connessione (ad esempio quando si tira il cavo).

In questi casi i messaggi ping possono essere usati come mezzo per verificare che il punto finale remoto sia ancora reattivo.

const WebSocket = require('ws');function noop() {}function heartbeat() { this.isAlive = true;}const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', function connection(ws) { ws.isAlive = true; ws.on('pong', heartbeat);});const interval = setInterval(function ping() { wss.clients.forEach(function each(ws) { if (ws.isAlive === false) return ws.terminate(); ws.isAlive = false; ws.ping(noop); });}, 30000);wss.on('close', function close() { clearInterval(interval);});

I messaggi ping sono inviati automaticamente in risposta ai messaggi ping come richiesto dalla specifica.

Proprio come l’esempio del server sopra i vostri client potrebbero anche perdere la connessione senza saperlo. Potreste voler aggiungere un ascoltatore di ping sui vostri client per evitarlo. Una semplice implementazione sarebbe:

const WebSocket = require('ws');function heartbeat() { clearTimeout(this.pingTimeout); // Use `WebSocket#terminate()`, which immediately destroys the connection, // instead of `WebSocket#close()`, which waits for the close timer. // Delay should be equal to the interval at which your server // sends out pings plus a conservative assumption of the latency. this.pingTimeout = setTimeout(() => { this.terminate(); }, 30000 + 1000);}const client = new WebSocket('wss://echo.websocket.org/');client.on('open', heartbeat);client.on('ping', heartbeat);client.on('close', function clear() { clearTimeout(this.pingTimeout);});

Come connettersi tramite un proxy?

Utilizzare un’implementazione http.Agent personalizzata come https-proxy-agent orsocks-proxy-agent.

Changelog

Stiamo usando i rilasci di GitHub per le voci del changelog.

Licenza

MIT

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *