hi i need to display total number of connected clients on my flask app i write this code for checking connected and disconnected connections.
app = Flask(__name__)
socketio = SocketIO(app)
clients = []
@socketio.on('connect', namespace='/')
def connect():
clients.append(request.namespace)
@socketio.on('disconnect', namespace='/')
def disconnect():
clients.remove(request.namespace)
then i render template like this
return render_template_string(TABLE_TEMPLATE, data=data, clients=len(clients))
In html part i call like this
<h1>{{ clients }} </h1>
but on webpage it keep showing 0
even client is connect i get output from client and it is connected it should print 1
2
depends how many clients are connected. even if i print this print(len(clients)) it return 0
. even my client is connect and i get output.
this is my updated code
from flask import Flask, request, render_template_string
from flask_socketio import SocketIO, emit
app = Flask(__name__)
socketio = SocketIO(app, logge=True)
clients = 0
@socketio.on("connect", namespace="/")
def connect():
# global variable as it needs to be shared
global clients
clients += 1
# emits a message with the user count anytime someone connects
emit("users", {"user_count": clients}, broadcast=True)
@socketio.on("disconnect", namespace="/")
def disconnect():
global clients
clients -= 1
emit("users", {"user_count": clients}, broadcast=True)
TABLE_TEMPLATE = """
<script
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
$(document).ready(function(){
var namespace = '/';
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
// Update the counter when a new user connects
socket.on('users', function(users) {
userCount = document.getElementById('user_counter');
userCount.innerHTML = users.user_count;
});
});
</script>
<h1 id='user_counter'></h1>
<style>
table, th, td {
border: 1px solid black;
}
</style>
<table style="width: 100%">
<thead>
<th>Client</th>
<th>IP</th>
<th>Status</th>
</thead>
<tbody>
{% for row in data %}
<tr>
<td><center>{{ row.client }}</td></center>
<td><center>{{ row.ip }}</td></center>
<td><center>{{ row.status }}</td></center>
</tr>
{% endfor %}
</tbody>
</table>
"""
@app.route("/device_add", methods=['POST'])
def device_add():
name = request.args.get('name')
with open('logs.log', 'a') as f:
f.write(f'{name} Connected USB from IP: {request.remote_addr} \n')
return 'ok'
@app.route("/device_remove", methods=['POST'])
def device_remove():
name = request.args.get('name')
with open('logs.log', 'a') as f:
f.write(f'{name} Disconnected USB from IP: {request.remote_addr}\n')
return 'ok'
@app.route("/", methods=['GET'])
def device_list():
keys = ['client', 'ip', 'status']
data = []
with open('logs.log', 'r') as f:
for line in f:
row = line.split()
data.append(dict(zip(keys, [row[0], row[-1], row[1]])))
return render_template_string(TABLE_TEMPLATE, data=data)
if __name__ == "__main__":
socketio.run(app)
Client Side :
import requests
import subprocess, string, time
import os
url = 'http://127.0.0.1:5000/'
name = os.uname()[1]
def on_device_add():
requests.post(f'{url}/device_add?name={name}')
def on_device_remove():
requests.post(f'{url}/device_remove?name={name}')
def detect_device(previous):
total = subprocess.run('lsblk | grep disk | wc -l', shell=True, stdout=subprocess.PIPE).stdout
time.sleep(3)
# if condition if new device add
if total > previous:
on_device_add()
# if no new device add or remove
elif total == previous:
detect_device(previous)
# if device remove
else:
on_device_remove()
# Infinite loop to keep client running.
while True:
detect_device(subprocess.run(' lsblk | grep disk | wc -l', shell=True , stdout=subprocess.PIPE).stdout)
After reading a bit of socket.io
documentation I've managed to spot the problems in your code.
Not a problem per-se, but incrementing/decrementing an int
counter is more than enough for this use case. Secondly, you don't have to pass that counter to the render_template
call as you're basically passing the user count before the conenct
event has had the opportunity to fire. You should emit a message (in this example with a users
topic) that will inform your page that something has changed:
from flask import Flask, request, render_template_string
from flask_socketio import SocketIO, emit
app = Flask(__name__)
socketio = SocketIO(app, logge=True)
clients = 0
@socketio.on("connect", namespace="/")
def connect():
# global variable as it needs to be shared
global clients
clients += 1
# emits a message with the user count anytime someone connects
emit("users", {"user_count": clients}, broadcast=True)
@socketio.on("disconnect", namespace="/")
def disconnect():
global clients
clients -= 1
emit("users", {"user_count": clients}, broadcast=True)
Moreover, you didn't open a connection to the socket in your template, this allows you to listen to the messages emitted by your socketio
decorators and update all connected clients. You will also need to write a bit of javascript to specify that the counter needs to be updated anytime a user connects/disconnects.
<!-- Remember to import socketio library -->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
$(document).ready(function(){
var namespace = '/';
var socket = io.connect('http://' + document.domain + ':' + location.port + namespace);
// Update the counter when a new user connects
socket.on('users', function(users) {
userCount = document.getElementById('user_counter');
userCount.innerHTML = users.user_count;
});
});
</script>
<h1 id='user_counter'></h1>
<!-- the rest of your template -->
This being said, you don't need to pass the counter value in your render_template
call. Also, from flask-socketio
docs , it seems to be good practice to start your app in the following way:
if __name__ == "__main__":
socketio.run(app)
Here a link to an edited version of your example.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.