twitst4tz

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

README.md (12904B)


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