Real-Time Application With Socket Programming

Kshitiz Bansal
5 min readJul 31, 2021

--

I offer an immense pleasure for you showing up here. Being a computer science devotee proficient in Microservices Development, Cloud Computing & Data Engineering, I have always looked forward in learning, sharing & gaining knowledge with overwhelming support of brilliant minds like you. With my deep regards, I hope this article will be able to reach out to the desire you wish to read ahead. Thankyou!

Kshitiz

If you are looking out to build an application which is able to send real time APIs’ responses (Backend to Frontend) then this article is where your search ends. We will be understanding the entire flow in a very summarized manner using Flask server and Python SocketIO module.

Backend Server

Consider this basic python flask server which has a microservice to return the multiplication table for a given integer. Currently it has no socket implemented and returns a one time post execution output.

from flask import Flask, request, jsonify
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/multiplication-table", methods=["POST"])def multiplication_table():
data = request.get_json()
number = data['number']
output = []
for i in range(1, 11):
v = str(number) + " X " + str(i) + " = " + str(number*i)
output.append(v)
return jsonify({'table': output}), 200
if __name__ == "__main__":
app.run(host='0.0.0.0', port='8080')

Frontend Client

For the above deployed server consider this javascript client in which we are printing the API’s output on the console for simplicity.

<!DOCTYPE html>
<html>
<body>
<form>
<input type="text" id="number" value="">
<input type="button" value="Submit" onclick="callapi()"/>
</form>
<script>
function callapi(){
var number = parseInt(document.getElementById('number').value);
const url = 'http://localhost:8080/multiplication-table';
const input = {
number: number
};
const request = new Request(url, {
method: 'POST',
body: JSON.stringify(input),
headers: new Headers({
'Content-Type': 'application/json'
})
});
fetch(request)
.then(res => res.json())
.then(res => console.log(res));
}
</script>
</body>
</html>

Output Screen

Socket Implementation

Now we will modify our existing microservice to send real time response along with execution. In order to do that, we will need additional server-client pair specifically for socket connections. The image below depicts the connection flow between backend and frontend but this time via socket server-client pair.

Socket Server

Here is our socket server which will consist of all necessary events that will act as messengers for backend and frontend communication.

from flask import Flask
from flask_socketio import SocketIO, join_room
import eventlet
eventlet.monkey_patch()
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins='*')
@socketio.on('join')
def on_join(user):
join_room(user)
@socketio.on('multiplication_table_server')
def listen(data=None):
if data:
socketio.emit('multiplication_table_client', data['data'], room=data['room'])
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=3030)

Socket Client

Once the socket server is up and running, we are good to implement socket client. Socket client is the one which will pass on all our messages to socket server, which will further emit to frontend client at provided room (user in this example).

from socketio import Clientsocket = Client(logger=True, engineio_logger=True)
socket.connect('http://localhost:3030')
def send_message(event, data, room):
data = {
"data": data,
"room": room
}
socket.emit(event, data)

Backend Server (Socket Implemented)

It is now time to update the microservice to enable it for sending real time logs. For this, socket client will be imported and logs will be passed accordingly.

from flask import Flask, request, jsonify
from flask_cors import CORS
from socket_client import send_message
app = Flask(__name__)
CORS(app)
@app.route("/multiplication-table", methods=["POST"])
def multiplication_table():
data = request.get_json()
number = data['number']
output = []
for i in range(1, 11):
v = str(number) + " X " + str(i) + " = " + str(number*i)
send_message("multiplication_table_server", v, "user1")
output.append(v)
return jsonify({'table': output}), 200
if __name__ == "__main__":
app.run(host='0.0.0.0', port='8080')

Frontend Client (Socket Implemented)

Just like the backend server is emitting the real time responses, frontend client should also be modified in order to continuously listen the server responses.

<!DOCTYPE html>
<html>
<body>
<form>
<input type="text" id="number" value="">
<input type="button" value="Submit" onclick="callapi()"/>
</form>
<script src="socket.io.js"></script>
<script>
let socket = io.connect('http://localhost:3030');
socket.emit('join', "user1");
socket.on("multiplication_table_client", (message) => {
console.log(message)
});

function callapi(){
var number = parseInt(document.getElementById('number').value);
const url = 'http://localhost:8080/multiplication-table';
const input = {
number: number
};
const request = new Request(url, {
method: 'POST',
body: JSON.stringify(input),
headers: new Headers({
'Content-Type': 'application/json'
})
});
fetch(request)
.then(res => res.json())
.then(res => console.log(res));
}
</script>
</body>
</html>

Output Screen (Socket Implemented)

Packages Required

These are the packages which worked for my requirement. Feel free to include/exclude with your necessity.

Python Packages

eventlet==0.31.0
Flask==1.1.2
Flask-API==2.0
Flask-Cors==3.0.9
Flask-SocketIO==5.1.0
greenlet==1.1.0
python-engineio==4.2.0
python-socketio==5.3.0
socketIO-client==0.7.2
socketIO-client-2==0.7.5
websocket-client==1.1.0
websockets==9.1
Werkzeug==1.0.1

Node.js Packages

react-websocket==2.1.0
socket.io-client==4.1.2
cors==2.8.5

Summary

The basic concept behind socket programming is to maintain a 2-way connection between server & client throughout the session. The moment frontend client connects with socket server, a room is joined which is nothing but a isolated socket connection maintained only for that room members. In the above example, user specific room are joined which makes the API responses available only to the actual user, and not all client users. Similarly, backend interacts with the client and passes the messages for a particular room. This approach reduces the latency and is majorly used in real time applications like messaging apps, live reporting etc.

Above code is fully tested & verified. With the provided snippets, you may need an additional ‘socket.io.js’ file which I have provided on my github portfolio.

--

--