WebSockets: Real-Time Communication for the Web

As web applications grow more interactive and real-time features become the norm — like chat apps, multiplayer games, notifications, or live updates — the need for persistent, two-way communication between client and server is more important than ever. This is where WebSockets shine.

What Are WebSockets?

WebSockets are a protocol providing full-duplex communication channels over a single, long-lived TCP connection. Unlike HTTP, which follows a request-response pattern, WebSockets allow both the server and client to send and receive messages anytime, without repeatedly opening new connections.

📡 WebSocket Lifecycle

  1. Client initiates a connection via HTTP handshake.
  2. Server upgrades the connection to WebSocket.
  3. Once established, data flows both ways.
  4. Connection stays open until either side closes it.

WebSockets vs HTTP

FeatureHTTPWebSocket
Communication ModelRequest-ResponseFull Duplex (bidirectional)
Connection TypeShort-livedPersistent
OverheadHigh (headers per req)Minimal (one-time handshake)
Real-time SupportPoor (needs polling)Excellent

Setting Up a WebSocket Server (Node.js)

Let’s look at how to create a basic WebSocket server using the popular ws library.

1. Install the library

bashCopyEditnpm install ws

2. Create the server

jsCopyEditconst WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });

server.on('connection', socket => {
  console.log('Client connected');

  socket.on('message', message => {
    console.log(`Received: ${message}`);
    socket.send(`Echo: ${message}`);
  });

  socket.on('close', () => {
    console.log('Client disconnected');
  });
});

Connecting from the Browser

jsCopyEditconst socket = new WebSocket('ws://localhost:8080');

socket.addEventListener('open', () => {
  console.log('Connected to server');
  socket.send('Hello Server!');
});

socket.addEventListener('message', event => {
  console.log('Message from server:', event.data);
});

Advanced WebSocket Concepts

1. Broadcasting Messages

You can broadcast a message to all connected clients like this:

jsCopyEditserver.clients.forEach(client => {
  if (client.readyState === WebSocket.OPEN) {
    client.send('Hello everyone!');
  }
});

2. Handling Heartbeats (Ping/Pong)

To detect dead clients and avoid memory leaks:

jsCopyEditfunction heartbeat() {
  this.isAlive = true;
}

server.on('connection', ws => {
  ws.isAlive = true;
  ws.on('pong', heartbeat);
});

setInterval(() => {
  server.clients.forEach(ws => {
    if (!ws.isAlive) return ws.terminate();

    ws.isAlive = false;
    ws.ping();
  });
}, 30000);

3. Authentication with WebSockets

Since WebSocket doesn’t inherently support headers like HTTP, you can pass tokens via query params or during the handshake:

jsCopyEditconst token = 'abc123';
const socket = new WebSocket(`ws://localhost:8080?token=${token}`);

Then verify it on the server:

jsCopyEditconst url = require('url');
server.on('connection', (ws, req) => {
  const params = new URLSearchParams(url.parse(req.url).query);
  const token = params.get('token');
  // Validate token...
});

Using WebSockets in Production

1. Security

  • Always use wss:// in production (WebSockets over TLS).
  • Validate and sanitize all input.
  • Implement proper authentication (JWTs, sessions, etc.).

2. Scalability

  • Use message brokers like Redis Pub/Sub for broadcasting across multiple nodes.
  • Consider using Socket.IO for easier scalability, fallbacks, and integrations.

Alternatives & Enhancements

TechnologyDescription
Socket.IOAbstraction over WebSockets with fallbacks
Server-Sent EventsOne-way communication from server to client
GraphQL SubscriptionsReal-time updates with GraphQL over WebSocket

Use Cases for WebSockets

  • Chat applications 🗨️
  • Live trading dashboards
  • Gaming servers
  • Collaborative editing tools
  • Live notifications
  • IoT device communication

Using WebSockets in Frameworks

React + WebSocket

jsxCopyEdit// WebSocketComponent.jsx
import React, { useEffect, useRef, useState } from 'react';

function WebSocketComponent() {
  const [messages, setMessages] = useState([]);
  const socketRef = useRef(null);

  useEffect(() => {
    socketRef.current = new WebSocket('ws://localhost:8080');

    socketRef.current.onopen = () => {
      console.log('Connected');
      socketRef.current.send('Hello from React!');
    };

    socketRef.current.onmessage = (event) => {
      setMessages(prev => [...prev, event.data]);
    };

    return () => socketRef.current.close();
  }, []);

  return (
    <div>
      <h2>Messages</h2>
      <ul>
        {messages.map((msg, i) => <li key={i}>{msg}</li>)}
      </ul>
    </div>
  );
}

export default WebSocketComponent;

Vue (Composition API)

vueCopyEdit<!-- WebSocketComponent.vue -->
<template>
  <div>
    <h2>Messages</h2>
    <ul>
      <li v-for="(msg, i) in messages" :key="i">{{ msg }}</li>
    </ul>
  </div>
</template>

<script setup>
import { onMounted, onUnmounted, ref } from 'vue';

const messages = ref([]);
let socket;

onMounted(() => {
  socket = new WebSocket('ws://localhost:8080');

  socket.onopen = () => {
    console.log('Connected');
    socket.send('Hello from Vue!');
  };

  socket.onmessage = (event) => {
    messages.value.push(event.data);
  };
});

onUnmounted(() => {
  if (socket) socket.close();
});
</script>

Angular (with RxJS and WebSocketSubject)

tsCopyEdit// websocket.service.ts
import { Injectable } from '@angular/core';
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';

@Injectable({ providedIn: 'root' })
export class WebSocketService {
  private socket$: WebSocketSubject<any>;

  constructor() {
    this.socket$ = webSocket('ws://localhost:8080');
  }

  sendMessage(msg: any) {
    this.socket$.next(msg);
  }

  getMessages() {
    return this.socket$.asObservable();
  }

  close() {
    this.socket$.complete();
  }
}
tsCopyEdit// websocket.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { WebSocketService } from './websocket.service';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-websocket',
  template: `
    <h2>Messages</h2>
    <ul>
      <li *ngFor="let msg of messages">{{ msg }}</li>
    </ul>
  `
})
export class WebSocketComponent implements OnInit, OnDestroy {
  messages: string[] = [];
  private sub: Subscription;

  constructor(private wsService: WebSocketService) {}

  ngOnInit() {
    this.sub = this.wsService.getMessages().subscribe(msg => {
      this.messages.push(msg);
    });

    this.wsService.sendMessage('Hello from Angular!');
  }

  ngOnDestroy() {
    this.sub.unsubscribe();
    this.wsService.close();
  }
}

Conclusion

WebSockets unlock a whole new level of interactivity for web applications. By maintaining a persistent connection between the client and server, WebSockets provide efficient, real-time communication — something traditional HTTP simply wasn’t built for.

With the right architecture and security practices in place, WebSockets can help build ultra-responsive, engaging apps for the modern web.

Share this content:

Hi, my name is Toni Naumoski, and I’m a Senior Frontend Developer with a passion for blending code and design. With years of experience as a Frontend Developer, Web Designer, and Creative Technologist, I specialize in crafting unique, responsive, and detail-oriented websites and web applications that stand out. I bring deep expertise in HTML, CSS, and JavaScript—working fluently with modern frameworks like React, Angular, and Vue, as well as animation libraries like GSAP. My creative side thrives in Photoshop and Figma, and I enjoy extending functionality using tools like Express.js and ChatGPT. My work is guided by high integrity, strong communication, a positive attitude, and a commitment to being a reliable collaborator. I take pride in delivering high-quality digital experiences that are both technically solid and visually compelling.

Post Comment