Websocket

Native WebSocket

WS - A NodeJS WebSocket library

WS is a WebSocket server for NodeJS. It's quite a low level: you listen to incoming connection requests and respond to raw messages as either strings or byte buffers. So you can consider it as a Native WebSocket in NodeJS world. Below are some examples of how you can create a WebSocket Server using WS

To install WS you can run the following command

npm install ws

Simple Server

import { WebSocketServer } from 'ws'

// Automatically create http server at port 8080
const wss = new WebSocketServer({ port: 8080 })

// listen for client connections
wss.on('connection', function connection(ws) {
  // listen for client sending messages
  ws.on('message', function message(data) {
    console.log('received: %s', data)
  })

  // send messages to client
  ws.send('something')
})

External HTTP Server

In case you want to use your own http server

import { createServer } from 'http'
import { WebSocketServer } from 'ws'

const server = createServer()

// Pass in the external server instance
const wss = new WebSocketServer({ server })

wss.on('connection', function connection(ws) {
  ws.on('message', function message(data) {
    console.log('received: %s', data)
  })

  ws.send('something')
})

server.listen(8080)

Multiple servers

This is a more complicated case when you want to have multiple WebSocket Servers sharing a single HTTP server for different purposes. In this case, you will need to handle upgrade requests on your own, but thankfully, WS also has a built-in handleUpgrade method so you just need to pass in the parameters.

import { createServer } from 'http'
import { parse } from 'url'
import { WebSocketServer } from 'ws'

const server = createServer()

// Remember to set noServer option to true
const wss1 = new WebSocketServer({ noServer: true })
const wss2 = new WebSocketServer({ noServer: true })

wss1.on('connection', function connection(ws) {
  // ...
})

wss2.on('connection', function connection(ws) {
  // ...
})

// Listern for upgrade requests from clients
server.on('upgrade', function upgrade(request, socket, head) {
  const { pathname } = parse(request.url)

  // Using built-in handleUpgrade method
  if (pathname === '/foo') {
    wss1.handleUpgrade(request, socket, head, function done(ws) {
      wss1.emit('connection', ws, request)
    })
  } else if (pathname === '/bar') {
    wss2.handleUpgrade(request, socket, head, function done(ws) {
      wss2.emit('connection', ws, request)
    })
  } else {
    socket.destroy()
  }
})

server.listen(8080)

WebSocket API

Modern browsers nowadays are all supported WebSocket API, so Front-end developers can integrate WebSocket into their applications without having to install any third-party libraries.

To create a WebSocket instance use the WebSocket() constructor.

WebSocket instance has 4 events that you should listen to:

  • open: triggered when the connection between the client and the server established
  • message: triggered when the WebSocket receives messages sent by the server
  • close: triggered when the connection is closed either by the client or the server
  • error: triggered when there are some errors

WebSocket also has 2 methods that you need to know:

  • close(): to close the connection
  • send(): to send the message to the server

See the below example for how to use WebSocket API in React

// Server Code
/*
const wss = new WebSocketServer({ noServer: true })
wss.on('connection', function connection(ws) {
ws.on('message', (data) => {
const stringData = data.toString()
if (stringData === 'Hi') {
ws.send('Hello')
}
})
})
*/
function WebSocketClient() {
const [messages, setMessages] = useState([])
const handleConnect = () => {
let connection = null
if (!('WebSocket' in window)) {
console.warn('WebSocket is not available on this browser')
}
connection = new WebSocket(`${WebSocketURI}/ws`)
connection.addEventListener('message', ({ data }) => {
setTimeout(() => {
try {
setMessages((m) => [...m, `Received: ${data}`])
connection.close()
} catch (error) {
console.log(error.message)
}
}, 1000)
})
connection.addEventListener('open', () => {
setMessages((m) => [...m, 'Connection established'])
setTimeout(() => {
connection.send('Hi')
setMessages((m) => [...m, 'Sent: Hi'])
}, 1000)
})
connection.addEventListener('close', () => {
setMessages((m) => [...m, 'Connection closed'])
})
connection.addEventListener('error', (err) => {
setMessages((m) => [...m, `Error: ${err.message}`])
})
}
return (
<div>
<Button onClick={handleConnect}>Connect</Button>
<div>
{messages.map((m) => (
<div key={m}>{m}</div>
))}
</div>
</div>
)
}
Previous
Introduction