Version npmBuildWindows x86 BuildDeckungsstatus

ws ist ein einfach zu bedienendes, rasend schnelle und gründlich getestete WebSocket-Client- und -Server-Implementierung.

Besteht die recht umfangreiche Autobahn-Testsuite: Server,Client.

Hinweis: Dieses Modul funktioniert nicht im Browser. Der Client in den Docs ist ein Verweis auf ein Backend, das die Rolle eines Clients in der WebSocket-Kommunikation übernimmt. Browser-Clients müssen das nativeWebSocketObjekt verwenden. Damit derselbe Code nahtlos auf Node.js und im Browser funktioniert, können Sie einen der vielen auf npm verfügbaren Wrapper wieisomorphic-ws verwenden.

Inhaltsverzeichnis

  • Protokollunterstützung
  • Installation
    • Opt-in für Leistung und Spezifikationskonformität
  • API-Dokumente
  • WebSocket-Kompression
  • Anwendungsbeispiele
    • Senden und Empfangen von Textdaten
    • Senden von binären Daten
    • Einfacher Server
    • Externer HTTP/S-Server
    • Mehrere Server, die sich einen einzigen HTTP/S-Server teilen
    • Client-Authentifizierung
    • Server-Broadcast
    • echo.websocket.org Demo
    • Verwendung der Node.js-Streams-API
    • Andere Beispiele
  • FAQ

    • Wie erhalte ich die IP-Adresse des Clients?
    • Wie erkenne und schließe ich abgebrochene Verbindungen?
    • Wie stelle ich eine Verbindung über einen Proxy her?
  • Changelog
  • Lizenz

Protokollunterstützung

  • HyBi-Drafts 07-12 (Verwenden Sie die Option protocolVersion: 8)
  • HyBi-Drafts 13-17 (Aktueller Standard, alternativ OptionprotocolVersion: 13)

Installieren

npm install ws

Opt-in für Performance und Spec-Compliance

Es gibt 2 optionale Module, die zusammen mit dem wsmodule installiert werden können. Diese Module sind binäre Zusätze, die bestimmte Operationen verbessern.

  • npm install --save-optional bufferutil Vorgefertigte Binärdateien sind für die gängigsten Plattformen verfügbar, sodass Sie nicht unbedingt einen C++-Compiler auf Ihrem Rechner installiert haben müssen: Ermöglicht es, effizient Operationen wie das Maskieren und Demaskieren der Daten-Nutzlast des WebSocket-Frames durchzuführen.
  • npm install --save-optional utf-8-validate: Ermöglicht es, effizient zu prüfen, ob eine Nachricht gültiges UTF-8 enthält, wie von der Spezifikation gefordert.

API-Dokumente

Siehe /doc/ws.md für Node.js-ähnliche Dokumentation von ws-Klassen und Utility-Funktionen.

WebSocket-Komprimierung

ws unterstützt die permessage-deflate-Erweiterung, die es dem Client und dem Server ermöglicht, einen Komprimierungsalgorithmus und seine Parameter auszuhandeln und ihn dann selektiv auf die Daten-Nutzlasten jeder WebSocket-Nachricht anzuwenden.

Die Erweiterung ist auf dem Server standardmäßig deaktiviert und auf dem Client standardmäßig aktiviert. Sie fügt einen erheblichen Overhead in Bezug auf Leistung und Speicherverbrauch hinzu, daher empfehlen wir, sie nur zu aktivieren, wenn sie wirklich benötigt wird.

Bitte beachten Sie, dass Node.js eine Reihe von Problemen mit der Hochleistungskomprimierung hat, bei der erhöhte Gleichzeitigkeit, insbesondere unter Linux, zu katastrophaler Speicherfragmentierung und langsamer Leistung führen kann. Wenn Sie beabsichtigen, permessage-deflate in der Produktion zu verwenden, lohnt es sich, einen Test einzurichten, der Ihre Arbeitslast repräsentiert und sicherstellt, dass Node.js/zlib diese mit akzeptabler Leistung und Speichernutzung bewältigt.

Das Tuning von permessage-deflate kann über die unten definierten Optionen vorgenommen werden. Sie können auch zlibDeflateOptions und zlibInflateOptions verwenden, die direkt in die Erstellung von rohen Deflate/Inflate-Streams übergeben werden.

Weitere Optionen finden Sie in der Dokumentation.

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

Der Client verwendet die Erweiterung nur, wenn sie auf dem Server unterstützt wird und aktiviert ist. Um die Erweiterung auf dem Client immer zu deaktivieren, setzen Sie dieperMessageDeflate Option auf false.

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

Anwendungsbeispiele

Senden und Empfangen von Textdaten

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

Senden von Binärdaten

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

Einfacher Server

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

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

Mehrere Server teilen sich einen einzigen HTTP/S-Server

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

Client-Authentifizierung

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

Siehe auch das mitgelieferte Beispiel mit express-session.

Server-Broadcast

Ein Client-WebSocket sendet an alle angeschlossenen WebSocket-Clients, inklusive sich selbst.

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

Ein Client-WebSocket sendet an alle anderen angeschlossenen WebSocket-Clients, außer sich selbst.

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

echo.websocket.org demo

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

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

Weitere Beispiele

Für ein vollständiges Beispiel mit einem Browser-Client, der mit einem ws-Server kommuniziert, siehe den Ordnerexamples.

Ansonsten siehe die Testfälle.

FAQ

Wie bekomme ich die IP-Adresse des Clients?

Die Remote-IP-Adresse kann aus dem Raw-Socket ermittelt werden.

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

Wenn der Server hinter einem Proxy wie NGINX läuft, ist es der De-facto-Standard, den X-Forwarded-For-Header zu verwenden.

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

Wie kann man unterbrochene Verbindungen erkennen und schließen?

Manchmal kann die Verbindung zwischen Server und Client auf eine Art und Weise unterbrochen werden, dass sowohl der Server als auch der Client nichts von dem unterbrochenen Zustand der Verbindung mitbekommen (z. B. beim Ziehen des Kabels).

In diesen Fällen können Ping-Nachrichten als Mittel verwendet werden, um zu überprüfen, ob der entfernte Endpunkt noch ansprechbar ist.

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

Als Antwort auf Ping-Nachrichten werden automatisch Ping-Nachrichten gesendet, so wie es die Spezifikation verlangt.

Genauso wie im obigen Server-Beispiel können Ihre Clients auch die Verbindung verlieren, ohne es zu wissen. Um dies zu verhindern, sollten Sie einen Ping-Listener auf Ihren Clients einrichten. Eine einfache Implementierung wäre:

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

Wie stellt man eine Verbindung über einen Proxy her?

Verwenden Sie eine eigene http.Agent-Implementierung wie https-proxy-agent odersocks-proxy-agent.

Changelog

Wir verwenden die GitHub-Versionen für Changelog-Einträge.

Lizenz

MIT

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.