What's Up With Websockets
July 22, 2025
Real-Time Logging with WebSockets and Socket.IO in Python
Welcome! If you're new here, part of the reason I started this blog was to reflect on and document key experiences from my software engineering career—what worked, what didn’t, and what I learned. Today’s post focuses on using WebSockets in Python, specifically through the Flask-SocketIO library.
I’ve built a number of RESTful APIs across industries including airlines, city government, and education. But recently, I explored a different pattern: WebSockets. This post serves both as a personal reference and a technical walkthrough for anyone looking to get started.
Background
I'm currently working with an automotive OEM to develop end-to-end testing procedures for in-car customer features. The test environment involves proprietary hardware and a software platform called CANoe, which is used to simulate ECU and multimedia platform behavior. However, all testing is manual and time-consuming—often taking over a week to validate functionality after a firmware update.
To improve this, I began building a Python-based proof of concept (POC) aimed at automating communication between users and the test hardware.
The POC had two initial goals:
- Establish ADB (Android Debug Bridge) communications with the hardware to send remote commands or execute scripts.
- Attach a minimal UI interface with live logging of backend activities.
After experimenting with both RESTful APIs and WebSockets, I found WebSockets to be better suited for real-time, continuous communication between the backend and frontend.
Why WebSockets?
WebSockets are ideal for scenarios requiring real-time, bi-directional communication. Unlike RESTful APIs, which are stateless and require a new connection for each transaction, WebSockets maintain a persistent connection. This allows the server to push messages to the client without polling or waiting for client-initiated requests.
For my use case—long-running tests and frequent logging—REST APIs didn’t cut it. They offered no insight into test progress until the request was completed. With WebSockets, I could stream log output live to the UI, giving immediate feedback and enabling interaction throughout the test.
What Are WebSockets?
A WebSocket is a communication protocol that enables two-way, persistent connections between a server and client. Unlike HTTP (used in REST APIs), which is unidirectional and requires constant handshakes, WebSockets:
- Use less overhead
- Stay open throughout a session
- Support real-time communication
This makes them perfect for chat applications, live dashboards, multiplayer games—and, in my case, real-time test logging.
Architecture Overview
The final POC stack consisted of:
- A Flask backend enhanced with
Flask-SocketIO - A ReactJS frontend with a simple UI for sending and receiving messages
- A centralized WebSocket utility, abstracted into custom
EmitterandSenderclasses - Minimal business logic and a scalable design that allows future modules to plug in
Design Principles
To centralize and encapsulate WebSocket logic, I created two core classes:
MessageEmitter– Responsible for low-level message emissionsMessageSender– Adds application-specific logic and formatting
Though only one client-server connection is currently needed, this design allows for clean separation of concerns and easy scaling in the future. I intentionally avoided using static or global socket references in favor of dependency injection.
The WebSocket Utility Classes
MessageEmitter.py
This class wraps the socketio.emit() function.
from flask_socketio import SocketIO
class MessageEmitter:
def __init__(self, socketio: SocketIO):
self.socketio = socketio
def emit(self, message):
self.socketio.emit('server_response', message)MessageSender.py
This class layers business logic on top of the emitter—for example, formatting logs with color.
from colorama import Fore
class MessageSender:
def __init__(self, emitter: MessageEmitter):
self.emitter = emitter
def send_message(self, message):
# Black on frontend, white on backend
colored_message = {"text": message, "color": "#000000"}
print(f"{Fore.WHITE}{message}{Fore.RESET}")
self.emitter.emit(colored_message)
def send_green_message(self, message):
# Green on frontend and backend
colored_message = {"text": message, "color": "#00bf0c"}
print(f"{Fore.GREEN}{message}{Fore.RESET}")
self.emitter.emit(colored_message)
# Add more methods here as neededThis setup allows different test modules to reuse the MessageEmitter while customizing how and what they send using their own version of MessageSender.
Flask Backend Setup
Inside main.py, the Flask app is wrapped with SocketIO:
from flask_socketio import SocketIO
from flask import Flask
app = Flask(__name__)
socketio = SocketIO(app)We then instantiate our utility classes:
emitter = MessageEmitter(socketio)
sender = MessageSender(emitter)Socket Event Handlers
These are the event hooks that define behavior when certain messages are received from the frontend:
@socketio.on('connect')
def handle_connect():
print("Client connected")
sender.send_green_message("Connected")
@socketio.on('disconnect')
def handle_disconnect():
print("Client disconnected")
@socketio.on('dcm_version_check')
def handle_adb_version_check():
print("Received DCM version check request")
adb_tools.version_check()
@socketio.on('client_message')
def handle_client_message(data):
print(f"Received message from client: {data}")
response = f"Processed: {data}"
emit('server_response', response)These handlers make the backend highly responsive, and because the socket remains open, the client sees updates in real time.
Frontend Integration
While frontend development isn’t my strongest area, I used a language model to help scaffold a simple ReactJS interface. It includes:
- Buttons to connect/disconnect from the backend
- Triggers to send test commands via WebSocket
- A display area to show incoming log messages with color-coded styling
This setup let me stay focused on the automation backend while still having a functional UI for interaction and debugging.
Final Thoughts
RESTful APIs and WebSockets each have their place. For real-time logging and interactivity during test automation, WebSockets proved the better choice. They significantly reduced test turnaround and improved observability.
While this POC currently handles a single client connection, the architecture is ready for future enhancements like:
- Managing multiple concurrent clients
- User-specific sessions
- Broadcasting or targeted messages
In short, WebSockets brought a level of responsiveness to this automation project that REST APIs couldn’t match. You can find the full code here.