Working with WebSockets

Loading

WebSockets provide full-duplex communication between a client and a server over a single TCP connection. Unlike traditional HTTP requests, WebSockets allow real-time, bidirectional communication, making them ideal for:
Chat applications
Live notifications
Real-time data streaming
Multiplayer gaming

Installing WebSocket Libraries

To work with WebSockets in Python, install websockets:

pip install websockets

1. Creating a WebSocket Server

A WebSocket server listens for connections and handles messages.

Simple WebSocket Server

import asyncio
import websockets

async def echo(websocket, path):
async for message in websocket:
await websocket.send(f"Server received: {message}")

# Start the WebSocket server on ws://localhost:8765
start_server = websockets.serve(echo, "localhost", 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

websockets.serve() → Starts the WebSocket server.
async for message in websocket → Listens for incoming messages.
await websocket.send() → Sends messages back to the client.


2. Creating a WebSocket Client

A WebSocket client connects to the server and exchanges messages.

import asyncio
import websockets

async def connect():
async with websockets.connect("ws://localhost:8765") as websocket:
await websocket.send("Hello Server!") # Send message
response = await websocket.recv() # Receive response
print(f"Server Response: {response}")

asyncio.run(connect())

✔ Connects to ws://localhost:8765.
✔ Sends "Hello Server!" and receives a response.


3. Handling Multiple Clients

Modify the server to handle multiple clients.

import asyncio
import websockets

connected_clients = set()

async def handle_client(websocket, path):
connected_clients.add(websocket)
try:
async for message in websocket:
for client in connected_clients:
if client != websocket:
await client.send(message) # Broadcast message
finally:
connected_clients.remove(websocket)

start_server = websockets.serve(handle_client, "localhost", 8765)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

connected_clients stores all active clients.
✔ Broadcasts received messages to all except the sender.


4. WebSockets with FastAPI

If using FastAPI, WebSockets can be handled with ease.

pythonCopyEditfrom fastapi import FastAPI, WebSocket
from typing import List

app = FastAPI()
clients: List[WebSocket] = []

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    clients.append(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            for client in clients:
                await client.send_text(f"Client says: {data}")
    except:
        clients.remove(websocket)

✔ FastAPI provides a websocket route at /ws.
✔ Clients are stored in a list and broadcast messages.

Connecting a WebSocket Client

Use JavaScript in the browser:

let socket = new WebSocket("ws://localhost:8000/ws");

socket.onmessage = function(event) {
console.log("Message from server:", event.data);
};

socket.onopen = function() {
socket.send("Hello from WebSocket client!");
};

✔ Connects to FastAPI WebSocket.
✔ Sends and receives messages.


5. WebSockets with Django (Django Channels)

Django doesn’t support WebSockets natively, so we use Django Channels.

Install Django Channels

pip install channels

Update settings.py

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"channels",
]

ASGI_APPLICATION = "myproject.asgi.application"

Create a WebSocket Consumer

In consumers.py:

import json
from channels.generic.websocket import AsyncWebsocketConsumer

class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
await self.accept()

async def receive(self, text_data):
data = json.loads(text_data)
await self.send(json.dumps({"message": data["message"]}))

✔ Handles WebSocket connect, receive, and send.

Route WebSockets in routing.py

from django.urls import re_path
from .consumers import ChatConsumer

websocket_urlpatterns = [
re_path(r'ws/chat/', ChatConsumer.as_asgi()),
]

Start Django ASGI Server

daphne -b 0.0.0.0 -p 8000 myproject.asgi:application

✔ WebSockets now work in Django! 🎉


6. WebSockets for Real-Time Notifications

Use WebSockets to send instant notifications to users.

WebSocket Server for Notifications

import asyncio
import websockets

async def notify_clients():
async with websockets.connect("ws://localhost:8765") as websocket:
while True:
await asyncio.sleep(5)
await websocket.send("🔔 New Notification!")

asyncio.run(notify_clients())

✔ Sends a notification every 5 seconds.
✔ Perfect for live updates & alerts.


7. WebSockets with Authentication

Protect WebSockets with authentication (JWT, tokens).

Token-Based Authentication in FastAPI

from fastapi import WebSocket, Depends

async def get_token(token: str):
if token != "mysecrettoken":
raise Exception("Unauthorized")

@app.websocket("/ws/{token}")
async def websocket_endpoint(websocket: WebSocket, token: str = Depends(get_token)):
await websocket.accept()
await websocket.send_text("✅ Authentication successful!")

✔ Checks token before accepting connection.
✔ Only users with valid tokens can connect.


8. Handling WebSocket Disconnections

Handle cases where clients disconnect unexpectedly.

async def handle_client(websocket, path):
try:
async for message in websocket:
print(f"Received: {message}")
except websockets.exceptions.ConnectionClosed:
print("Client disconnected")

✔ Detects connection loss and handles errors.


9. Scaling WebSockets with Redis

Use Redis for scalable WebSockets across multiple servers.

Install Redis & Channels Redis

pip install channels-redis

Configure settings.py for Redis

CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("127.0.0.1", 6379)],
},
},
}

✔ Enables WebSocket messaging across multiple servers.


10. WebSockets vs REST APIs

FeatureWebSocketsREST APIs
CommunicationBidirectionalRequest-Response
LatencyLow (Real-time)Higher
Best ForChats, Live DataStandard API Calls
PerformanceMore EfficientLess Efficient
ScalabilityNeeds RedisEasier to Scale

Leave a Reply

Your email address will not be published. Required fields are marked *