Blame view

node_modules/ws/README.md 11.3 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
  # ws: a Node.js WebSocket library
  
  [![Version npm](https://img.shields.io/npm/v/ws.svg)](https://www.npmjs.com/package/ws)
  [![Linux Build](https://img.shields.io/travis/websockets/ws/master.svg)](https://travis-ci.org/websockets/ws)
  [![Windows Build](https://ci.appveyor.com/api/projects/status/github/websockets/ws?branch=master&svg=true)](https://ci.appveyor.com/project/lpinca/ws)
  [![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg)](https://coveralls.io/r/websockets/ws?branch=master)
  
  ws is a simple to use, blazing fast, and thoroughly tested WebSocket client
  and server implementation.
  
  Passes the quite extensive Autobahn test suite: [server][server-report],
  [client][client-report].
  
  **Note**: This module does not work in the browser. The client in the docs is a
  reference to a back end with the role of a client in the WebSocket
  communication. Browser clients must use the native
  [`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) object.
  To make the same code work seamlessly on Node.js and the browser, you can use
  one of the many wrappers available on npm, like
  [isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
  
  ## Table of Contents
  
  * [Protocol support](#protocol-support)
  * [Installing](#installing)
    + [Opt-in for performance and spec compliance](#opt-in-for-performance-and-spec-compliance)
  * [API docs](#api-docs)
  * [WebSocket compression](#websocket-compression)
  * [Usage examples](#usage-examples)
    + [Sending and receiving text data](#sending-and-receiving-text-data)
    + [Sending binary data](#sending-binary-data)
    + [Server example](#server-example)
    + [Broadcast example](#broadcast-example)
    + [ExpressJS example](#expressjs-example)
    + [echo.websocket.org demo](#echowebsocketorg-demo)
    + [Other examples](#other-examples)
  * [Error handling best practices](#error-handling-best-practices)
  * [FAQ](#faq)
    + [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client)
    + [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections)
    + [How to connect via a proxy?](#how-to-connect-via-a-proxy)
  * [Changelog](#changelog)
  * [License](#license)
  
  ## Protocol support
  
  * **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
  * **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`)
  
  ## Installing
  
  ```
  npm install --save ws
  ```
  
  ### Opt-in for performance and spec compliance
  
  There are 2 optional modules that can be installed along side with the ws
  module. These modules are binary addons which improve certain operations.
  Prebuilt binaries are available for the most popular platforms so you don't
  necessarily need to have a C++ compiler installed on your machine.
  
  - `npm install --save-optional bufferutil`: Allows to efficiently perform
    operations such as masking and unmasking the data payload of the WebSocket
    frames.
  - `npm install --save-optional utf-8-validate`: Allows to efficiently check
    if a message contains valid UTF-8 as required by the spec.
  
  ## API docs
  
  See [`/doc/ws.md`](./doc/ws.md) for Node.js-like docs for the ws classes.
  
  ## WebSocket compression
  
  ws supports the [permessage-deflate extension][permessage-deflate] which
  enables the client and server to negotiate a compression algorithm and its
  parameters, and then selectively apply it to the data payloads of each
  WebSocket message.
  
  The extension is disabled by default on the server and enabled by default on
  the client. It adds a significant overhead in terms of performance and memory
  consumption so we suggest to enable it only if it is really needed.
  
  Note that Node.js has a variety of issues with high-performance compression,
  where increased concurrency, especially on Linux, can lead to
  [catastrophic memory fragmentation][node-zlib-bug] and slow performance.
  If you intend to use permessage-deflate in production, it is worthwhile to set
  up a test representative of your workload and ensure Node.js/zlib will handle
  it with acceptable performance and memory usage.
  
  Tuning of permessage-deflate can be done via the options defined below. You can
  also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly
  into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs].
  
  See [the docs][ws-server-options] for more options.
  
  ```js
  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.
      clientMaxWindowBits: 10,       // 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.
    }
  });
  ```
  
  The client will only use the extension if it is supported and enabled on the
  server. To always disable the extension on the client set the
  `perMessageDeflate` option to `false`.
  
  ```js
  const WebSocket = require('ws');
  
  const ws = new WebSocket('ws://www.host.com/path', {
    perMessageDeflate: false
  });
  ```
  
  ## Usage examples
  
  ### Sending and receiving text data
  
  ```js
  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);
  });
  ```
  
  ### Sending binary data
  
  ```js
  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] = i / 2;
    }
  
    ws.send(array);
  });
  ```
  
  ### Server example
  
  ```js
  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');
  });
  ```
  
  ### Broadcast example
  
  ```js
  const WebSocket = require('ws');
  
  const wss = new WebSocket.Server({ port: 8080 });
  
  // Broadcast to all.
  wss.broadcast = function broadcast(data) {
    wss.clients.forEach(function each(client) {
      if (client.readyState === WebSocket.OPEN) {
        client.send(data);
      }
    });
  };
  
  wss.on('connection', function connection(ws) {
    ws.on('message', function incoming(data) {
      // Broadcast to everyone else.
      wss.clients.forEach(function each(client) {
        if (client !== ws && client.readyState === WebSocket.OPEN) {
          client.send(data);
        }
      });
    });
  });
  ```
  
  ### ExpressJS example
  
  ```js
  const express = require('express');
  const http = require('http');
  const url = require('url');
  const WebSocket = require('ws');
  
  const app = express();
  
  app.use(function (req, res) {
    res.send({ msg: "hello" });
  });
  
  const server = http.createServer(app);
  const wss = new WebSocket.Server({ server });
  
  wss.on('connection', function connection(ws, req) {
    const location = url.parse(req.url, true);
    // You might use location.query.access_token to authenticate or share sessions
    // or req.headers.cookie (see http://stackoverflow.com/a/16395220/151312)
  
    ws.on('message', function incoming(message) {
      console.log('received: %s', message);
    });
  
    ws.send('something');
  });
  
  server.listen(8080, function listening() {
    console.log('Listening on %d', server.address().port);
  });
  ```
  
  ### echo.websocket.org demo
  
  ```js
  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);
  });
  ```
  
  ### Other examples
  
  For a full example with a browser client communicating with a ws server, see the
  examples folder.
  
  Otherwise, see the test cases.
  
  ## Error handling best practices
  
  ```js
  // If the WebSocket is closed before the following send is attempted
  ws.send('something');
  
  // Errors (both immediate and async write errors) can be detected in an optional
  // callback. The callback is also the only way of being notified that data has
  // actually been sent.
  ws.send('something', function ack(error) {
    // If error is not defined, the send has been completed, otherwise the error
    // object will indicate what failed.
  });
  
  // Immediate errors can also be handled with `try...catch`, but **note** that
  // since sends are inherently asynchronous, socket write failures will *not* be
  // captured when this technique is used.
  try { ws.send('something'); }
  catch (e) { /* handle error */ }
  ```
  
  ## FAQ
  
  ### How to get the IP address of the client?
  
  The remote IP address can be obtained from the raw socket.
  
  ```js
  const WebSocket = require('ws');
  
  const wss = new WebSocket.Server({ port: 8080 });
  
  wss.on('connection', function connection(ws, req) {
    const ip = req.connection.remoteAddress;
  });
  ```
  
  When the server runs behind a proxy like NGINX, the de-facto standard is to use
  the `X-Forwarded-For` header.
  
  ```js
  wss.on('connection', function connection(ws, req) {
    const ip = req.headers['x-forwarded-for'];
  });
  ```
  
  ### How to detect and close broken connections?
  
  Sometimes the link between the server and the client can be interrupted in a
  way that keeps both the server and the client unaware of the broken state of the
  connection (e.g. when pulling the cord).
  
  In these cases ping messages can be used as a means to verify that the remote
  endpoint is still responsive.
  
  ```js
  const WebSocket = require('ws');
  
  const wss = new WebSocket.Server({ port: 8080 });
  
  function noop() {}
  
  function heartbeat() {
    this.isAlive = true;
  }
  
  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);
  ```
  
  Pong messages are automatically sent in response to ping messages as required
  by the spec.
  
  ### How to connect via a proxy?
  
  Use a custom `http.Agent` implementation like [https-proxy-agent][] or
  [socks-proxy-agent][].
  
  ## Changelog
  
  We're using the GitHub [releases][changelog] for changelog entries.
  
  ## License
  
  [MIT](LICENSE)
  
  [https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
  [socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
  [client-report]: http://websockets.github.io/ws/autobahn/clients/
  [server-report]: http://websockets.github.io/ws/autobahn/servers/
  [permessage-deflate]: https://tools.ietf.org/html/rfc7692
  [changelog]: https://github.com/websockets/ws/releases
  [node-zlib-bug]: https://github.com/nodejs/node/issues/8871
  [node-zlib-deflaterawdocs]: https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
  [ws-server-options]: https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback