In the previous article about websockets, we have discussed websockets as a full-duplex protocol for communication interchange. It is used where we want real-time updates of data like chat applications, live scores, IoT, etc. After that, we learned how to implement websockets in our Django application using Django channels.
In this article, we will discuss socket programming using Django socketio. SocketIO is a library that enables low-latency, bidirectional and event-based communication between a client and a server. You will find the SocketIO library implemented in almost all languages like Javascript, Python, Java, GoLang, etc. it is built on top of the WebSocket protocol and provides additional guarantees like a fallback to HTTP long-polling or automatic reconnection.
Table of Contents
Django socketio
Django socketio is a Django project that brings together a variety of features that allow you to use WebSockets seamlessly with any Django project. It is built on top of gevent-socketio which is a Python implementation of SocketIO protocol. One aim of this project is to provide a single gevent-based API that works across the different WSGI-based web frameworks out there (Pyramid, Pylons, Flask, web2py, Django, etc…). Only ~3 lines of code are required to tie-in gevent-socketio in your framework. Note: you need to use the gevent python WSGI server to use gevent-socketio.
Installation
If you’ve never installed gevent, you’ll first need to install the libevent development library. You may also need the Python development library if not installed. This can be achieved on Debian-based systems with the following commands:
sudo apt-get install python-dev sudo apt-get install libevent-dev
Now to install Django-socketio you have to install it through Pypi using pip by running the following command
pip install django-socketio
After the installation, you can add django_socketio in your INSTALLED_APPS and add django_socketio.url in your URLs config.
# settings.py INSTALLED_APPS = [ ... 'django_socketio' ] # urls.py urlpatterns += [ url('', include('django_socketio.urls')) ]
The client-side Javascript for socketio can be added to the templates using socketio template tags.
<head> {% load socketio_tags %} {% socketio %} <script> const socket = new io.Socket(); socket.connect(); // etc </script> </head>
Now your Django socketio app is configured and you can run the server by running runserver_socketio management command
python manage.py runserve_socketio host:port
Where default host and port can be configured in settings.py file by SOCKETIO_HOST and SOCKETIO_PORT variables respectively. But if host and port arguments are passed in the command, they will always take precedence.
Channels
Gevent-socketio provides two ways to send messages to the client; one is using socket.send that will send a message to a specific client and the other is socket.broadcast which will broadcast the message across all the connected clients.
A common practice in websockets is to divide the communication into channels to maintain privacy and maintainability. Just like chat rooms, instead of broadcasting messages to all chat rooms, we broadcast it to specific clients in a chat room.
Django-socketio provides methods on both the client and server-side to receive and send messages in a channel.
Subscribing to a channel in the client
let socket = new io.Socket(); socket.connect(); socket.on('connect', function() { socket.subscribe('<channel-name>'); });
After a client is subscribed to a channel, you can broadcast the message in the channel by using socket.broadcast_channel method.
socket.broadcast_channel(message, channel='<channel-name>')
Methods of sending messages
Django socketio provides multiple methods to send message to a specific client or broadcast it to a group of clients:
- socket.send(message) – this is implemented by gevent-socketio. It is used to send message directly to the socket
- socket.broadcast(message) – this is also implemented by gevent-socketio and it is used to broadcast the message to all sockets
These methods are provided by django socketio:
- socket.broadcast_channel(message, channel=None) – sends the given message to all the clients connected to the given channel. If no channel is given, the message is broadcast to all clients.
- socket.send_and_broadcast(message) – sends message to all the clients including the sender
- socket.send_and_broadcast_channel(message, channel=None) – sends message to all the clients subscribed to the given channel and the sender.
Looking to Hire a Django developer
Share the details of your request and we will provide you with a full-cycle team under one roof.
Events
Django socketio provides some events that we can subscribe to. Each of these events is triggered at the relevant stage of the socketio operation. These are the main parts of handling your logic for socketio.
from django_socketio.events import on_message @on_message def message_received(request, socket, context, **kwargs): ...
In order for django-socketio to recognize and subscribe to these events, you should write these in events.py file in your relevant apps just like you do with views.py and models.py.
Each event handler takes three parameters, first one is request which is the current request in-flight, the second one is socket instance for which the event is occurred and the context which is simply a dictionary that can be used to persist variables across all events throughout the life-cycle of a single WebSocket connection.
Socketio operations lifecycle events
- on_connect(request, socket, context) – triggered first when the connection is established
- on_message(request, socket, context, message) – triggers every time the message is sent by the client. Message argument will have the received message
- on_subscribe(request, socket, context, channel) – triggers when a client is subscribed to a channel. Channel argument contains the subscribed channel
- on_unsubscribe(request, socket, context, channel) – triggers when a client is unsubscribed from a specified channel
- on_error(request, socket, context, exception) – trigger when an error occurs. Exception parameter contains the error that was raised
- on_disconnect(request, socket, context) – triggered when a client is disconnected
- on_finish(request, socket, context) – triggered when socketio request is finished
Registering events to a specific channel
All the events except the on_connect event can take channel arguments in the decorator. The channel argument can contain a regex of the channel name.
For example, if you have two different message handlers for different channels, you can do this:
from django_socketio.events import on_message @on_message(channel='test1') def test_message(request, socket, context, message): ... @on_message(channel='test2') def other_test_message(request, socket, context, message): ...