buddy

node MVC discord bot
Log | Files | Refs | README

README.md (13967B)


      1 # ws: a Node.js WebSocket library
      2 
      3 [![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws)
      4 [![Build](https://img.shields.io/travis/websockets/ws/master.svg?logo=travis)](https://travis-ci.com/websockets/ws)
      5 [![Windows x86 Build](https://img.shields.io/appveyor/ci/lpinca/ws/master.svg?logo=appveyor)](https://ci.appveyor.com/project/lpinca/ws)
      6 [![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg)](https://coveralls.io/github/websockets/ws)
      7 
      8 ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and
      9 server implementation.
     10 
     11 Passes the quite extensive Autobahn test suite: [server][server-report],
     12 [client][client-report].
     13 
     14 **Note**: This module does not work in the browser. The client in the docs is a
     15 reference to a back end with the role of a client in the WebSocket
     16 communication. Browser clients must use the native
     17 [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
     18 object. To make the same code work seamlessly on Node.js and the browser, you
     19 can use one of the many wrappers available on npm, like
     20 [isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
     21 
     22 ## Table of Contents
     23 
     24 - [Protocol support](#protocol-support)
     25 - [Installing](#installing)
     26   - [Opt-in for performance and spec compliance](#opt-in-for-performance-and-spec-compliance)
     27 - [API docs](#api-docs)
     28 - [WebSocket compression](#websocket-compression)
     29 - [Usage examples](#usage-examples)
     30   - [Sending and receiving text data](#sending-and-receiving-text-data)
     31   - [Sending binary data](#sending-binary-data)
     32   - [Simple server](#simple-server)
     33   - [External HTTP/S server](#external-https-server)
     34   - [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server)
     35   - [Client authentication](#client-authentication)
     36   - [Server broadcast](#server-broadcast)
     37   - [echo.websocket.org demo](#echowebsocketorg-demo)
     38   - [Use the Node.js streams API](#use-the-nodejs-streams-api)
     39   - [Other examples](#other-examples)
     40 - [FAQ](#faq)
     41   - [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client)
     42   - [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections)
     43   - [How to connect via a proxy?](#how-to-connect-via-a-proxy)
     44 - [Changelog](#changelog)
     45 - [License](#license)
     46 
     47 ## Protocol support
     48 
     49 - **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
     50 - **HyBi drafts 13-17** (Current default, alternatively option
     51   `protocolVersion: 13`)
     52 
     53 ## Installing
     54 
     55 ```
     56 npm install ws
     57 ```
     58 
     59 ### Opt-in for performance and spec compliance
     60 
     61 There are 2 optional modules that can be installed along side with the ws
     62 module. These modules are binary addons which improve certain operations.
     63 Prebuilt binaries are available for the most popular platforms so you don't
     64 necessarily need to have a C++ compiler installed on your machine.
     65 
     66 - `npm install --save-optional bufferutil`: Allows to efficiently perform
     67   operations such as masking and unmasking the data payload of the WebSocket
     68   frames.
     69 - `npm install --save-optional utf-8-validate`: Allows to efficiently check if a
     70   message contains valid UTF-8 as required by the spec.
     71 
     72 ## API docs
     73 
     74 See [`/doc/ws.md`](./doc/ws.md) for Node.js-like documentation of ws classes and
     75 utility functions.
     76 
     77 ## WebSocket compression
     78 
     79 ws supports the [permessage-deflate extension][permessage-deflate] which enables
     80 the client and server to negotiate a compression algorithm and its parameters,
     81 and then selectively apply it to the data payloads of each WebSocket message.
     82 
     83 The extension is disabled by default on the server and enabled by default on the
     84 client. It adds a significant overhead in terms of performance and memory
     85 consumption so we suggest to enable it only if it is really needed.
     86 
     87 Note that Node.js has a variety of issues with high-performance compression,
     88 where increased concurrency, especially on Linux, can lead to [catastrophic
     89 memory fragmentation][node-zlib-bug] and slow performance. If you intend to use
     90 permessage-deflate in production, it is worthwhile to set up a test
     91 representative of your workload and ensure Node.js/zlib will handle it with
     92 acceptable performance and memory usage.
     93 
     94 Tuning of permessage-deflate can be done via the options defined below. You can
     95 also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly
     96 into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs].
     97 
     98 See [the docs][ws-server-options] for more options.
     99 
    100 ```js
    101 const WebSocket = require('ws');
    102 
    103 const wss = new WebSocket.Server({
    104   port: 8080,
    105   perMessageDeflate: {
    106     zlibDeflateOptions: {
    107       // See zlib defaults.
    108       chunkSize: 1024,
    109       memLevel: 7,
    110       level: 3
    111     },
    112     zlibInflateOptions: {
    113       chunkSize: 10 * 1024
    114     },
    115     // Other options settable:
    116     clientNoContextTakeover: true, // Defaults to negotiated value.
    117     serverNoContextTakeover: true, // Defaults to negotiated value.
    118     serverMaxWindowBits: 10, // Defaults to negotiated value.
    119     // Below options specified as default values.
    120     concurrencyLimit: 10, // Limits zlib concurrency for perf.
    121     threshold: 1024 // Size (in bytes) below which messages
    122     // should not be compressed.
    123   }
    124 });
    125 ```
    126 
    127 The client will only use the extension if it is supported and enabled on the
    128 server. To always disable the extension on the client set the
    129 `perMessageDeflate` option to `false`.
    130 
    131 ```js
    132 const WebSocket = require('ws');
    133 
    134 const ws = new WebSocket('ws://www.host.com/path', {
    135   perMessageDeflate: false
    136 });
    137 ```
    138 
    139 ## Usage examples
    140 
    141 ### Sending and receiving text data
    142 
    143 ```js
    144 const WebSocket = require('ws');
    145 
    146 const ws = new WebSocket('ws://www.host.com/path');
    147 
    148 ws.on('open', function open() {
    149   ws.send('something');
    150 });
    151 
    152 ws.on('message', function incoming(data) {
    153   console.log(data);
    154 });
    155 ```
    156 
    157 ### Sending binary data
    158 
    159 ```js
    160 const WebSocket = require('ws');
    161 
    162 const ws = new WebSocket('ws://www.host.com/path');
    163 
    164 ws.on('open', function open() {
    165   const array = new Float32Array(5);
    166 
    167   for (var i = 0; i < array.length; ++i) {
    168     array[i] = i / 2;
    169   }
    170 
    171   ws.send(array);
    172 });
    173 ```
    174 
    175 ### Simple server
    176 
    177 ```js
    178 const WebSocket = require('ws');
    179 
    180 const wss = new WebSocket.Server({ port: 8080 });
    181 
    182 wss.on('connection', function connection(ws) {
    183   ws.on('message', function incoming(message) {
    184     console.log('received: %s', message);
    185   });
    186 
    187   ws.send('something');
    188 });
    189 ```
    190 
    191 ### External HTTP/S server
    192 
    193 ```js
    194 const fs = require('fs');
    195 const https = require('https');
    196 const WebSocket = require('ws');
    197 
    198 const server = https.createServer({
    199   cert: fs.readFileSync('/path/to/cert.pem'),
    200   key: fs.readFileSync('/path/to/key.pem')
    201 });
    202 const wss = new WebSocket.Server({ server });
    203 
    204 wss.on('connection', function connection(ws) {
    205   ws.on('message', function incoming(message) {
    206     console.log('received: %s', message);
    207   });
    208 
    209   ws.send('something');
    210 });
    211 
    212 server.listen(8080);
    213 ```
    214 
    215 ### Multiple servers sharing a single HTTP/S server
    216 
    217 ```js
    218 const http = require('http');
    219 const WebSocket = require('ws');
    220 const url = require('url');
    221 
    222 const server = http.createServer();
    223 const wss1 = new WebSocket.Server({ noServer: true });
    224 const wss2 = new WebSocket.Server({ noServer: true });
    225 
    226 wss1.on('connection', function connection(ws) {
    227   // ...
    228 });
    229 
    230 wss2.on('connection', function connection(ws) {
    231   // ...
    232 });
    233 
    234 server.on('upgrade', function upgrade(request, socket, head) {
    235   const pathname = url.parse(request.url).pathname;
    236 
    237   if (pathname === '/foo') {
    238     wss1.handleUpgrade(request, socket, head, function done(ws) {
    239       wss1.emit('connection', ws, request);
    240     });
    241   } else if (pathname === '/bar') {
    242     wss2.handleUpgrade(request, socket, head, function done(ws) {
    243       wss2.emit('connection', ws, request);
    244     });
    245   } else {
    246     socket.destroy();
    247   }
    248 });
    249 
    250 server.listen(8080);
    251 ```
    252 
    253 ### Client authentication
    254 
    255 ```js
    256 const http = require('http');
    257 const WebSocket = require('ws');
    258 
    259 const server = http.createServer();
    260 const wss = new WebSocket.Server({ noServer: true });
    261 
    262 wss.on('connection', function connection(ws, request, client) {
    263   ws.on('message', function message(msg) {
    264     console.log(`Received message ${msg} from user ${client}`);
    265   });
    266 });
    267 
    268 server.on('upgrade', function upgrade(request, socket, head) {
    269   // This function is not defined on purpose. Implement it with your own logic.
    270   authenticate(request, (err, client) => {
    271     if (err || !client) {
    272       socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
    273       socket.destroy();
    274       return;
    275     }
    276 
    277     wss.handleUpgrade(request, socket, head, function done(ws) {
    278       wss.emit('connection', ws, request, client);
    279     });
    280   });
    281 });
    282 
    283 server.listen(8080);
    284 ```
    285 
    286 Also see the provided [example][session-parse-example] using `express-session`.
    287 
    288 ### Server broadcast
    289 
    290 A client WebSocket broadcasting to all connected WebSocket clients, including
    291 itself.
    292 
    293 ```js
    294 const WebSocket = require('ws');
    295 
    296 const wss = new WebSocket.Server({ port: 8080 });
    297 
    298 wss.on('connection', function connection(ws) {
    299   ws.on('message', function incoming(data) {
    300     wss.clients.forEach(function each(client) {
    301       if (client.readyState === WebSocket.OPEN) {
    302         client.send(data);
    303       }
    304     });
    305   });
    306 });
    307 ```
    308 
    309 A client WebSocket broadcasting to every other connected WebSocket clients,
    310 excluding itself.
    311 
    312 ```js
    313 const WebSocket = require('ws');
    314 
    315 const wss = new WebSocket.Server({ port: 8080 });
    316 
    317 wss.on('connection', function connection(ws) {
    318   ws.on('message', function incoming(data) {
    319     wss.clients.forEach(function each(client) {
    320       if (client !== ws && client.readyState === WebSocket.OPEN) {
    321         client.send(data);
    322       }
    323     });
    324   });
    325 });
    326 ```
    327 
    328 ### echo.websocket.org demo
    329 
    330 ```js
    331 const WebSocket = require('ws');
    332 
    333 const ws = new WebSocket('wss://echo.websocket.org/', {
    334   origin: 'https://websocket.org'
    335 });
    336 
    337 ws.on('open', function open() {
    338   console.log('connected');
    339   ws.send(Date.now());
    340 });
    341 
    342 ws.on('close', function close() {
    343   console.log('disconnected');
    344 });
    345 
    346 ws.on('message', function incoming(data) {
    347   console.log(`Roundtrip time: ${Date.now() - data} ms`);
    348 
    349   setTimeout(function timeout() {
    350     ws.send(Date.now());
    351   }, 500);
    352 });
    353 ```
    354 
    355 ### Use the Node.js streams API
    356 
    357 ```js
    358 const WebSocket = require('ws');
    359 
    360 const ws = new WebSocket('wss://echo.websocket.org/', {
    361   origin: 'https://websocket.org'
    362 });
    363 
    364 const duplex = WebSocket.createWebSocketStream(ws, { encoding: 'utf8' });
    365 
    366 duplex.pipe(process.stdout);
    367 process.stdin.pipe(duplex);
    368 ```
    369 
    370 ### Other examples
    371 
    372 For a full example with a browser client communicating with a ws server, see the
    373 examples folder.
    374 
    375 Otherwise, see the test cases.
    376 
    377 ## FAQ
    378 
    379 ### How to get the IP address of the client?
    380 
    381 The remote IP address can be obtained from the raw socket.
    382 
    383 ```js
    384 const WebSocket = require('ws');
    385 
    386 const wss = new WebSocket.Server({ port: 8080 });
    387 
    388 wss.on('connection', function connection(ws, req) {
    389   const ip = req.socket.remoteAddress;
    390 });
    391 ```
    392 
    393 When the server runs behind a proxy like NGINX, the de-facto standard is to use
    394 the `X-Forwarded-For` header.
    395 
    396 ```js
    397 wss.on('connection', function connection(ws, req) {
    398   const ip = req.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
    399 });
    400 ```
    401 
    402 ### How to detect and close broken connections?
    403 
    404 Sometimes the link between the server and the client can be interrupted in a way
    405 that keeps both the server and the client unaware of the broken state of the
    406 connection (e.g. when pulling the cord).
    407 
    408 In these cases ping messages can be used as a means to verify that the remote
    409 endpoint is still responsive.
    410 
    411 ```js
    412 const WebSocket = require('ws');
    413 
    414 function noop() {}
    415 
    416 function heartbeat() {
    417   this.isAlive = true;
    418 }
    419 
    420 const wss = new WebSocket.Server({ port: 8080 });
    421 
    422 wss.on('connection', function connection(ws) {
    423   ws.isAlive = true;
    424   ws.on('pong', heartbeat);
    425 });
    426 
    427 const interval = setInterval(function ping() {
    428   wss.clients.forEach(function each(ws) {
    429     if (ws.isAlive === false) return ws.terminate();
    430 
    431     ws.isAlive = false;
    432     ws.ping(noop);
    433   });
    434 }, 30000);
    435 
    436 wss.on('close', function close() {
    437   clearInterval(interval);
    438 });
    439 ```
    440 
    441 Pong messages are automatically sent in response to ping messages as required by
    442 the spec.
    443 
    444 Just like the server example above your clients might as well lose connection
    445 without knowing it. You might want to add a ping listener on your clients to
    446 prevent that. A simple implementation would be:
    447 
    448 ```js
    449 const WebSocket = require('ws');
    450 
    451 function heartbeat() {
    452   clearTimeout(this.pingTimeout);
    453 
    454   // Use `WebSocket#terminate()`, which immediately destroys the connection,
    455   // instead of `WebSocket#close()`, which waits for the close timer.
    456   // Delay should be equal to the interval at which your server
    457   // sends out pings plus a conservative assumption of the latency.
    458   this.pingTimeout = setTimeout(() => {
    459     this.terminate();
    460   }, 30000 + 1000);
    461 }
    462 
    463 const client = new WebSocket('wss://echo.websocket.org/');
    464 
    465 client.on('open', heartbeat);
    466 client.on('ping', heartbeat);
    467 client.on('close', function clear() {
    468   clearTimeout(this.pingTimeout);
    469 });
    470 ```
    471 
    472 ### How to connect via a proxy?
    473 
    474 Use a custom `http.Agent` implementation like [https-proxy-agent][] or
    475 [socks-proxy-agent][].
    476 
    477 ## Changelog
    478 
    479 We're using the GitHub [releases][changelog] for changelog entries.
    480 
    481 ## License
    482 
    483 [MIT](LICENSE)
    484 
    485 [changelog]: https://github.com/websockets/ws/releases
    486 [client-report]: http://websockets.github.io/ws/autobahn/clients/
    487 [https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
    488 [node-zlib-bug]: https://github.com/nodejs/node/issues/8871
    489 [node-zlib-deflaterawdocs]:
    490   https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
    491 [permessage-deflate]: https://tools.ietf.org/html/rfc7692
    492 [server-report]: http://websockets.github.io/ws/autobahn/servers/
    493 [session-parse-example]: ./examples/express-session-parse
    494 [socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
    495 [ws-server-options]:
    496   https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback