isomorfeus-transport 2.0.6 → 2.0.10

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