Real-Time Application With Socket Programming
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 CORSapp = 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}), 200if __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 eventleteventlet.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_messageapp = 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}), 200if __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.
Thanks again for spending those precious couple of minutes of yours reading the article. For any query or suggestion please feel free to reach out: