简体   繁体   中英

how to get connected clients in flask

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM