Wersja npmBuildWindows x86 BuildStan pokrycia

ws jest prostym w użyciu, bardzo szybką i dokładnie przetestowaną implementacją klienta i serwera WebSocket.

Przechodzi dość obszerny zestaw testów Autobahn: server,client.

Uwaga: Ten moduł nie działa w przeglądarce. Klient w dokumentach jest odniesieniem do back-endu pełniącego rolę klienta w komunikacji WebSocket. Klienci przeglądarki muszą używać natywnegoWebSocketobject. Aby ten sam kod działał bezproblemowo w Node.js i przeglądarce, możesz użyć jednego z wielu wrapperów dostępnych na npm, jakisomorphic-ws.

Spis treści

  • Obsługa protokołów
  • Instalacja
    • Opt-in dla wydajności i zgodności ze specyfikacją
  • Dokumenty API
  • Kompresja WebSocket
  • Przykłady użycia
    • Wysyłanie i odbieranie danych tekstowych
    • Wysyłanie danych binarnych
    • Wysyłanie danych binarnych danych binarnych
    • Proste serwery
    • Zewnętrzny serwer HTTP/S
    • Wielokrotne współdzielenie jednego serwera HTTP/S
    • Uwierzytelnianie klienta
    • Rozgłaszanie przez serwer
    • echo.websocket.org demo
    • Użyj API strumieni Node.js streams API
    • Inne przykłady
  • FAQ
    • Jak uzyskać adres IP klienta?
    • Jak wykrywać i zamykać zerwane połączenia?
    • Jak łączyć się przez proxy?
  • Changelog
  • Licencja

Obsługa protokołów

  • HyBi drafts 07-12 (Użyj opcji protocolVersion: 8)
  • HyBi drafts 13-17 (Obecna opcja domyślna, alternatywnie opcjaprotocolVersion: 13)

Instalacja

npm install ws

Opcja dla wydajności i zgodności ze specyfikacją

Istnieją 2 opcjonalne moduły, które można zainstalować wraz z modułem wsm. Moduły te są binarnymi dodatkami, które poprawiają pewne operacje.Prebuilt binaries są dostępne dla najpopularniejszych platform, więc nie musisz mieć zainstalowanego kompilatora C++ na swoim komputerze.

  • npm install --save-optional bufferutil: Pozwala na sprawne wykonywanie operacji takich jak maskowanie i demaskowanie ładunku danych w ramkach WebSocket.
  • npm install --save-optional utf-8-validate: Umożliwia efektywne sprawdzenie, czy wiadomość zawiera prawidłowy UTF-8, jak wymaga tego specyfikacja.

Dokumenty API

Zobacz /doc/ws.md dla dokumentacji klas ws i funkcji użytkowych w stylu Node.js.

Kompresja WebSocket

ws obsługuje rozszerzenie permessage-deflate, które pozwala klientowi i serwerowi negocjować algorytm kompresji i jego parametry, a następnie selektywnie stosować go do ładunku danych każdej wiadomości WebSocket.

Rozszerzenie jest domyślnie wyłączone na serwerze i domyślnie włączone na kliencie. Dodaje ono znaczący narzut w zakresie wydajności i zużycia pamięci, więc sugerujemy włączać je tylko wtedy, gdy jest naprawdę potrzebne.

Zauważ, że Node.js ma wiele problemów z wysokowydajną kompresją, gdzie zwiększona współbieżność, szczególnie na Linuksie, może prowadzić do katastrofalnej fragmentacji pamięci i powolnej wydajności. Jeśli zamierzasz używać permessage-deflate w produkcji, warto jest skonfigurować test reprezentujący obciążenie i upewnić się, że Node.js/zlib poradzi sobie z nim z akceptowalną wydajnością i zużyciem pamięci.

Dostrajanie permessage-deflate może być wykonane poprzez opcje zdefiniowane poniżej. Możesz również użyć zlibDeflateOptions i zlibInflateOptions, który jest przekazywany bezpośrednio do tworzenia surowych strumieni deflate/inflate.

Zobacz dokumenty, aby uzyskać więcej opcji.

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

Klient będzie używał rozszerzenia tylko wtedy, gdy jest ono obsługiwane i włączone na serwerze. Aby zawsze wyłączać rozszerzenie na kliencie ustaw opcjęperMessageDeflate na false.

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

Przykłady użycia

Wysyłanie i odbieranie danych tekstowych

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

Wysyłanie danych binarnych

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

Prosty serwer

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

Zewnętrzny Serwer HTTP/S

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

Wiele serwerów współdzielących pojedynczy serwer 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);

Uwierzytelnianie klienta

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

Sprawdź również podany przykład z użyciem express-session.

Rozgłaszanie przez serwer

Klient WebSocket rozgłaszający do wszystkich podłączonych klientów WebSocket, włączając w to siebie.

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

Klient WebSocket rozgłaszający do wszystkich innych podłączonych klientów WebSocket, wyłączając siebie.

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

Używanie interfejsu API 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);

Inne przykłady

Pełny przykład z klientem przeglądarkowym komunikującym się z serwerem ws znajdziesz w folderze theexamples.

W przeciwnym razie zobacz przypadki testowe.

FAQ

Jak uzyskać adres IP klienta?

Zdalny adres IP można uzyskać z surowego gniazda.

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

Gdy serwer działa za proxy jak NGINX, standardem jest użycie nagłówka X-Forwarded-For.

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

Jak wykrywać i zamykać zerwane połączenia?

Czasami połączenie między serwerem a klientem może zostać przerwane w taki sposób, że zarówno serwer jak i klient nie są świadomi zerwanego stanu połączenia (np. przy pociągnięciu za linkę).

W takich przypadkach wiadomości ping mogą być użyte jako środek do weryfikacji, czy zdalny punkt końcowy nadal odpowiada.

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

Wiadomości ping są automatycznie wysyłane w odpowiedzi na wiadomości ping zgodnie z wymaganiami specyfikacji.

Tak jak w przykładzie z serwerem powyżej, twoi klienci mogą równie dobrze stracić połączenie nie wiedząc o tym. Możesz chcieć dodać listener ping na swoich klientach, aby temu zapobiec. Prostą implementacją byłoby:

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

Jak połączyć się przez proxy?

Użyj niestandardowej http.Agent implementacji jak https-proxy-agent lubsocks-proxy-agent.

Changelog

Używamy wydań z GitHuba do wpisów w changelogu.

Licencja

MIT

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *