Harnessing WebSockets in Python: A Guide for Real-Time Web Communication

code.surgery
6 min readMay 9, 2023

The world of web development has come a long way since the days of simple static websites. Today, web applications often require real-time, two-way communication between servers and clients. This is where WebSockets come in, providing a persistent connection for exchanging data. In this post, we will be focusing on how to harness the power of WebSockets using Python, a versatile and beginner-friendly programming language.

WebSockets: A Brief Introduction

WebSockets is a communications protocol that provides a full-duplex (two-way), persistent connection between a client and a server. Unlike HTTP, which is a request-response-based protocol, WebSockets allows the server to push data to the client even without a formal request. This makes it ideal for applications that require real-time data exchange, such as live chats, online gaming, and real-time marketplaces.

WebSockets and Python

Python, being a multi-paradigm programming language, can handle WebSocket communication quite effectively. There are several libraries available in Python for managing WebSocket connections, such as websocket, websockets, and socket.io. For this post, we'll focus on the websockets library, a robust and easy-to-use choice for WebSocket communications in Python.

Setting up Python and WebSockets

Before diving into the code, ensure you have the correct environment set up. Install the websockets library using pip:

pip install websockets

Implementing a WebSocket Server in Python

Let’s create a simple echo server that sends back the received message.

import asyncio
import websockets

async def echo(websocket, path):
async for message in websocket:
await websocket.send(message)

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

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

In the script above, we define a simple asynchronous function echo that listens for incoming messages and then sends the same message back. We then create a WebSocket server that listens to connections on localhost on port 8765.

Implementing a WebSocket Client in Python

Now, let’s implement a simple client that sends a message to the server and waits for the response.

import asyncio
import websockets

async def hello():
uri = "ws://localhost:8765"
async with websockets.connect(uri) as websocket:
message = input("What's your message? ")
await websocket.send(message)
response = await websocket.recv()
print(f"Received from server: {response}")

asyncio.get_event_loop().run_until_complete(hello())

In this script, we create a WebSocket client that connects to the server we created earlier. We then get a message from the user, send it to the server, wait for a response, and print the response.

Flask-SocketIO: Real-Time Communication in Flask Applications

Now, let’s move beyond basic Python and explore how we can use WebSockets in a Flask application with the Flask-SocketIO library.

Flask-SocketIO is a Flask extension that provides support for handling Socket.IO, a JavaScript library for real-time web applications. It provides a simple way to manage WebSocket connections and even falls back on HTTP long-polling in situations where a WebSocket connection cannot be established.

To use Flask-SocketIO, you need to install both Flask and Flask-SocketIO using pip:

pip install flask flask-socketio

Let’s create a simple server application using Flask and Flask-SocketIO:

from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
socketio = SocketIO(app)

@app.route('/')
def index():
return render_template('index.html')

@socketio.on('message')
def handle_message(data):
print('received message: ' + data)
emit('response', 'This is a response')

if __name__ == '__main__':
socketio.run(app, host='localhost', port=5000)

In this application, we define a route / that returns an index.html template. We also define a SocketIO event handler for 'message' events that prints the received message and emits a 'response' event with a message.

The index.html file could look something like this:

<!DOCTYPE html>
<html>
<head>
<title>WebSocket Demo</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.4/socket.io.js"></script>
<script type="text/javascript" charset="utf-8">
var socket = io.connect('http://localhost:5000');
socket.on('connect', function() {
socket.emit('message', 'User has connected!');
});
socket.on('response', function(msg) {
alert(msg);
});
</script>
</head>
<body>
<h1>WebSocket Demo</h1>
</body>
</html>

In this HTML, we use the Socket.IO JavaScript client library to establish a connection to the server when the page loads. We emit a ‘message’ event with a welcome message and define a handler for ‘response’ events that alerts the received message.

Understanding Python and Websockets: A Deep Dive

By understanding the strengths and weaknesses of Python in the realm of WebSocket servers, you can make an informed decision about whether it’s the right fit for your project.

Pros and Cons of Using Python for WebSocket Servers

Pros

  1. Ease of Use: Python is renowned for its simplicity and readability, which makes it a great choice for developers of all skill levels. The websockets and flask-socketio libraries further enhance Python's usability by providing straightforward interfaces for handling WebSocket connections.
  2. Asynchronous Support: Python’s asyncio library and the native async/await syntax provide powerful tools for handling concurrent tasks, which is crucial for real-time applications.
  3. Robust Libraries: Python offers a wide range of libraries and frameworks that support WebSocket communication, giving developers the flexibility to choose the most suitable one for their needs.
  4. Wide Community Support: Python has a large and active community. This means more resources, tutorials, and help available for troubleshooting issues.

Cons

  1. Performance: While Python is easy to use, it may not be as performant as other languages like C++ or Rust when it comes to handling a large number of simultaneous WebSocket connections. This is due to the Global Interpreter Lock (GIL) in Python, which can limit its ability to fully utilize multi-core processors.
  2. Not Native Web Technology: Unlike JavaScript, Python is not a native web technology. It means that if you want to use Python for WebSocket server-side and JavaScript for the client-side, developers need to be comfortable in both languages.
  3. Synchronous Nature: Python’s design is fundamentally synchronous. While the asyncio library helps introduce asynchrony, it may not feel as natural or be as efficient as event-driven languages like Node.js.
  4. Scalability: Due to the previously mentioned performance issues, Python might face some difficulties when scaling up to handle a large number of WebSocket connections.

Comparing Python to specific technologies:

  • Node.js: Node.js, being event-driven, is naturally suitable for handling WebSocket connections and can handle a large number of simultaneous connections more efficiently. However, Python’s readability and simplicity can make it a better choice for developers who value ease of use and rapid development.
  • Rust: Rust provides superior performance and memory safety while maintaining high-level abstractions, making it a strong choice for highly concurrent WebSocket servers. However, Rust has a steeper learning curve than Python, which could slow down development speed for those unfamiliar with the language.
  • Scala: Scala, running on the Java Virtual Machine (JVM), offers strong support for concurrency and can deliver high performance, but its syntax and functional programming model might be more complex to learn compared to Python. The Play Framework in Scala has built-in support for handling WebSockets.
  • Java: Java has robust support for WebSockets and can deliver high performance, but its verbosity and complexity can make it harder to work with compared to Python.

Choosing the Right Technology: What to Consider?

When it comes to choosing the right technology for your WebSocket server, it’s essential to consider the specific requirements of your application and the strengths of your development team.

Project Requirements: If your application requires handling a large number of simultaneous WebSocket connections, you might want to consider a technology known for its high performance and concurrency management, such as Rust or Node.js. However, if you’re building a smaller-scale application or prototyping, Python’s simplicity and speed of development could be more beneficial.

Team Expertise: The skills and experience of your development team are crucial factors. If your team is already proficient in Python and less familiar with other technologies, the time and effort required to learn a new language might outweigh the potential performance benefits.

Maintenance and Scalability: Consider the long-term maintenance and scalability of your project. While Python might be quicker for initial development, other languages may offer better performance and easier scalability as your application grows.

Community and Support: A vibrant community and strong support can be a lifesaver when you run into problems. Python, Node.js, and Java all have large communities with lots of resources, while Rust and Scala, although growing, are newer and have smaller communities.

Conclusion

While Python has some fantastic libraries for working with WebSockets and is renowned for its readability and ease of use, it’s crucial to consider your specific use case before selecting your technology. Performance, scalability, and the nature of your application are all important considerations.

Remember, the best technology is the one that suits your specific needs and context. A language is just a tool, and the best tool depends on the job at hand. While Python might not be the best fit for every WebSocket application, it’s a powerful, flexible, and friendly language that’s certainly worth considering.

By integrating WebSocket functionality into our Python applications, we can create real-time, interactive web applications that can handle a wide range of tasks, from live chat systems to real-time data updates, and much more.

Happy coding!

--

--

code.surgery

"Code.Surgery here: coder, tech-enthusiast, and writer. Dissecting programming languages, simplifying complex concepts. Join me as we operate on code!"