1 # ws: a Node.js WebSocket library
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)
8 ws is a simple to use, blazing fast, and thoroughly tested WebSocket client
9 and server implementation.
11 Passes the quite extensive Autobahn test suite: [server][server-report],
12 [client][client-report].
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) object.
18 To make the same code work seamlessly on Node.js and the browser, you can use
19 one of the many wrappers available on npm, like
20 [isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
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)
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)
48 * **HyBi drafts 07-12** (Use the option `protocolVersion: 8`)
49 * **HyBi drafts 13-17** (Current default, alternatively option `protocolVersion: 13`)
57 ### Opt-in for performance and spec compliance
59 There are 2 optional modules that can be installed along side with the ws
60 module. These modules are binary addons which improve certain operations.
61 Prebuilt binaries are available for the most popular platforms so you don't
62 necessarily need to have a C++ compiler installed on your machine.
64 - `npm install --save-optional bufferutil`: Allows to efficiently perform
65 operations such as masking and unmasking the data payload of the WebSocket
67 - `npm install --save-optional utf-8-validate`: Allows to efficiently check
68 if a message contains valid UTF-8 as required by the spec.
72 See [`/doc/ws.md`](./doc/ws.md) for Node.js-like docs for the ws classes.
74 ## WebSocket compression
76 ws supports the [permessage-deflate extension][permessage-deflate] which
77 enables the client and server to negotiate a compression algorithm and its
78 parameters, and then selectively apply it to the data payloads of each
81 The extension is disabled by default on the server and enabled by default on
82 the 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.
85 Note that Node.js has a variety of issues with high-performance compression,
86 where increased concurrency, especially on Linux, can lead to
87 [catastrophic memory fragmentation][node-zlib-bug] and slow performance.
88 If you intend to use permessage-deflate in production, it is worthwhile to set
89 up a test representative of your workload and ensure Node.js/zlib will handle
90 it with acceptable performance and memory usage.
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].
96 See [the docs][ws-server-options] for more options.
99 const WebSocket = require('ws');
101 const wss = new WebSocket.Server({
104 zlibDeflateOptions: { // See zlib defaults.
109 zlibInflateOptions: {
112 // Other options settable:
113 clientNoContextTakeover: true, // Defaults to negotiated value.
114 serverNoContextTakeover: true, // Defaults to negotiated value.
115 clientMaxWindowBits: 10, // 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.
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`.
130 const WebSocket = require('ws');
132 const ws = new WebSocket('ws://www.host.com/path', {
133 perMessageDeflate: false
139 ### Sending and receiving text data
142 const WebSocket = require('ws');
144 const ws = new WebSocket('ws://www.host.com/path');
146 ws.on('open', function open() {
147 ws.send('something');
150 ws.on('message', function incoming(data) {
155 ### Sending binary data
158 const WebSocket = require('ws');
160 const ws = new WebSocket('ws://www.host.com/path');
162 ws.on('open', function open() {
163 const array = new Float32Array(5);
165 for (var i = 0; i < array.length; ++i) {
176 const WebSocket = require('ws');
178 const wss = new WebSocket.Server({ port: 8080 });
180 wss.on('connection', function connection(ws) {
181 ws.on('message', function incoming(message) {
182 console.log('received: %s', message);
185 ws.send('something');
189 ### External HTTP/S server
192 const fs = require('fs');
193 const https = require('https');
194 const WebSocket = require('ws');
196 const server = new https.createServer({
197 cert: fs.readFileSync('/path/to/cert.pem'),
198 key: fs.readFileSync('/path/to/key.pem')
200 const wss = new WebSocket.Server({ server });
202 wss.on('connection', function connection(ws) {
203 ws.on('message', function incoming(message) {
204 console.log('received: %s', message);
207 ws.send('something');
213 ### Multiple servers sharing a single HTTP/S server
216 const http = require('http');
217 const WebSocket = require('ws');
219 const server = http.createServer();
220 const wss1 = new WebSocket.Server({ noServer: true });
221 const wss2 = new WebSocket.Server({ noServer: true });
223 wss1.on('connection', function connection(ws) {
227 wss2.on('connection', function connection(ws) {
231 server.on('upgrade', function upgrade(request, socket, head) {
232 const pathname = url.parse(request.url).pathname;
234 if (pathname === '/foo') {
235 wss1.handleUpgrade(request, socket, head, function done(ws) {
236 wss1.emit('connection', ws, request);
238 } else if (pathname === '/bar') {
239 wss2.handleUpgrade(request, socket, head, function done(ws) {
240 wss2.emit('connection', ws, request);
253 const WebSocket = require('ws');
255 const wss = new WebSocket.Server({ port: 8080 });
258 wss.broadcast = function broadcast(data) {
259 wss.clients.forEach(function each(client) {
260 if (client.readyState === WebSocket.OPEN) {
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) {
278 ### echo.websocket.org demo
281 const WebSocket = require('ws');
283 const ws = new WebSocket('wss://echo.websocket.org/', {
284 origin: 'https://websocket.org'
287 ws.on('open', function open() {
288 console.log('connected');
292 ws.on('close', function close() {
293 console.log('disconnected');
296 ws.on('message', function incoming(data) {
297 console.log(`Roundtrip time: ${Date.now() - data} ms`);
299 setTimeout(function timeout() {
307 For a full example with a browser client communicating with a ws server, see the
310 Otherwise, see the test cases.
312 ## Error handling best practices
315 // If the WebSocket is closed before the following send is attempted
316 ws.send('something');
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.
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 { ws.send('something'); }
330 catch (e) { /* handle error */ }
335 ### How to get the IP address of the client?
337 The remote IP address can be obtained from the raw socket.
340 const WebSocket = require('ws');
342 const wss = new WebSocket.Server({ port: 8080 });
344 wss.on('connection', function connection(ws, req) {
345 const ip = req.connection.remoteAddress;
349 When the server runs behind a proxy like NGINX, the de-facto standard is to use
350 the `X-Forwarded-For` header.
353 wss.on('connection', function connection(ws, req) {
354 const ip = req.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
358 ### How to detect and close broken connections?
360 Sometimes the link between the server and the client can be interrupted in a
361 way that keeps both the server and the client unaware of the broken state of the
362 connection (e.g. when pulling the cord).
364 In these cases ping messages can be used as a means to verify that the remote
365 endpoint is still responsive.
368 const WebSocket = require('ws');
370 const wss = new WebSocket.Server({ port: 8080 });
374 function heartbeat() {
378 wss.on('connection', function connection(ws) {
380 ws.on('pong', heartbeat);
383 const interval = setInterval(function ping() {
384 wss.clients.forEach(function each(ws) {
385 if (ws.isAlive === false) return ws.terminate();
393 Pong messages are automatically sent in response to ping messages as required
396 ### How to connect via a proxy?
398 Use a custom `http.Agent` implementation like [https-proxy-agent][] or
399 [socks-proxy-agent][].
403 We're using the GitHub [releases][changelog] for changelog entries.
409 [https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
410 [socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
411 [client-report]: http://websockets.github.io/ws/autobahn/clients/
412 [server-report]: http://websockets.github.io/ws/autobahn/servers/
413 [permessage-deflate]: https://tools.ietf.org/html/rfc7692
414 [changelog]: https://github.com/websockets/ws/releases
415 [node-zlib-bug]: https://github.com/nodejs/node/issues/8871
416 [node-zlib-deflaterawdocs]: https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
417 [ws-server-options]: https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback