twitst4tz

twitter statistics web application
Log | Files | Refs | README | LICENSE

README.md (13836B)


      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 [![Linux Build](https://img.shields.io/travis/websockets/ws/master.svg?logo=travis)](https://travis-ci.com/websockets/ws)
      5 [![Windows 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   authenticate(request, (err, client) => {
    270     if (err || !client) {
    271       socket.destroy();
    272       return;
    273     }
    274 
    275     wss.handleUpgrade(request, socket, head, function done(ws) {
    276       wss.emit('connection', ws, request, client);
    277     });
    278   });
    279 });
    280 
    281 server.listen(8080);
    282 ```
    283 
    284 Also see the provided [example][session-parse-example] using `express-session`.
    285 
    286 ### Server broadcast
    287 
    288 A client WebSocket broadcasting to all connected WebSocket clients, including
    289 itself.
    290 
    291 ```js
    292 const WebSocket = require('ws');
    293 
    294 const wss = new WebSocket.Server({ port: 8080 });
    295 
    296 wss.on('connection', function connection(ws) {
    297   ws.on('message', function incoming(data) {
    298     wss.clients.forEach(function each(client) {
    299       if (client.readyState === WebSocket.OPEN) {
    300         client.send(data);
    301       }
    302     });
    303   });
    304 });
    305 ```
    306 
    307 A client WebSocket broadcasting to every other connected WebSocket clients,
    308 excluding itself.
    309 
    310 ```js
    311 const WebSocket = require('ws');
    312 
    313 const wss = new WebSocket.Server({ port: 8080 });
    314 
    315 wss.on('connection', function connection(ws) {
    316   ws.on('message', function incoming(data) {
    317     wss.clients.forEach(function each(client) {
    318       if (client !== ws && client.readyState === WebSocket.OPEN) {
    319         client.send(data);
    320       }
    321     });
    322   });
    323 });
    324 ```
    325 
    326 ### echo.websocket.org demo
    327 
    328 ```js
    329 const WebSocket = require('ws');
    330 
    331 const ws = new WebSocket('wss://echo.websocket.org/', {
    332   origin: 'https://websocket.org'
    333 });
    334 
    335 ws.on('open', function open() {
    336   console.log('connected');
    337   ws.send(Date.now());
    338 });
    339 
    340 ws.on('close', function close() {
    341   console.log('disconnected');
    342 });
    343 
    344 ws.on('message', function incoming(data) {
    345   console.log(`Roundtrip time: ${Date.now() - data} ms`);
    346 
    347   setTimeout(function timeout() {
    348     ws.send(Date.now());
    349   }, 500);
    350 });
    351 ```
    352 
    353 ### Use the Node.js streams API
    354 
    355 ```js
    356 const WebSocket = require('ws');
    357 
    358 const ws = new WebSocket('wss://echo.websocket.org/', {
    359   origin: 'https://websocket.org'
    360 });
    361 
    362 const duplex = WebSocket.createWebSocketStream(ws, { encoding: 'utf8' });
    363 
    364 duplex.pipe(process.stdout);
    365 process.stdin.pipe(duplex);
    366 ```
    367 
    368 ### Other examples
    369 
    370 For a full example with a browser client communicating with a ws server, see the
    371 examples folder.
    372 
    373 Otherwise, see the test cases.
    374 
    375 ## FAQ
    376 
    377 ### How to get the IP address of the client?
    378 
    379 The remote IP address can be obtained from the raw socket.
    380 
    381 ```js
    382 const WebSocket = require('ws');
    383 
    384 const wss = new WebSocket.Server({ port: 8080 });
    385 
    386 wss.on('connection', function connection(ws, req) {
    387   const ip = req.connection.remoteAddress;
    388 });
    389 ```
    390 
    391 When the server runs behind a proxy like NGINX, the de-facto standard is to use
    392 the `X-Forwarded-For` header.
    393 
    394 ```js
    395 wss.on('connection', function connection(ws, req) {
    396   const ip = req.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
    397 });
    398 ```
    399 
    400 ### How to detect and close broken connections?
    401 
    402 Sometimes the link between the server and the client can be interrupted in a way
    403 that keeps both the server and the client unaware of the broken state of the
    404 connection (e.g. when pulling the cord).
    405 
    406 In these cases ping messages can be used as a means to verify that the remote
    407 endpoint is still responsive.
    408 
    409 ```js
    410 const WebSocket = require('ws');
    411 
    412 function noop() {}
    413 
    414 function heartbeat() {
    415   this.isAlive = true;
    416 }
    417 
    418 const wss = new WebSocket.Server({ port: 8080 });
    419 
    420 wss.on('connection', function connection(ws) {
    421   ws.isAlive = true;
    422   ws.on('pong', heartbeat);
    423 });
    424 
    425 const interval = setInterval(function ping() {
    426   wss.clients.forEach(function each(ws) {
    427     if (ws.isAlive === false) return ws.terminate();
    428 
    429     ws.isAlive = false;
    430     ws.ping(noop);
    431   });
    432 }, 30000);
    433 
    434 wss.on('close', function close() {
    435   clearInterval(interval);
    436 });
    437 ```
    438 
    439 Pong messages are automatically sent in response to ping messages as required by
    440 the spec.
    441 
    442 Just like the server example above your clients might as well lose connection
    443 without knowing it. You might want to add a ping listener on your clients to
    444 prevent that. A simple implementation would be:
    445 
    446 ```js
    447 const WebSocket = require('ws');
    448 
    449 function heartbeat() {
    450   clearTimeout(this.pingTimeout);
    451 
    452   // Use `WebSocket#terminate()`, which immediately destroys the connection,
    453   // instead of `WebSocket#close()`, which waits for the close timer.
    454   // Delay should be equal to the interval at which your server
    455   // sends out pings plus a conservative assumption of the latency.
    456   this.pingTimeout = setTimeout(() => {
    457     this.terminate();
    458   }, 30000 + 1000);
    459 }
    460 
    461 const client = new WebSocket('wss://echo.websocket.org/');
    462 
    463 client.on('open', heartbeat);
    464 client.on('ping', heartbeat);
    465 client.on('close', function clear() {
    466   clearTimeout(this.pingTimeout);
    467 });
    468 ```
    469 
    470 ### How to connect via a proxy?
    471 
    472 Use a custom `http.Agent` implementation like [https-proxy-agent][] or
    473 [socks-proxy-agent][].
    474 
    475 ## Changelog
    476 
    477 We're using the GitHub [releases][changelog] for changelog entries.
    478 
    479 ## License
    480 
    481 [MIT](LICENSE)
    482 
    483 [changelog]: https://github.com/websockets/ws/releases
    484 [client-report]: http://websockets.github.io/ws/autobahn/clients/
    485 [https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
    486 [node-zlib-bug]: https://github.com/nodejs/node/issues/8871
    487 [node-zlib-deflaterawdocs]:
    488   https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
    489 [permessage-deflate]: https://tools.ietf.org/html/rfc7692
    490 [server-report]: http://websockets.github.io/ws/autobahn/servers/
    491 [session-parse-example]: ./examples/express-session-parse
    492 [socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
    493 [ws-server-options]:
    494   https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback