如何在烧瓶中获得连接的客户端

时间:2020-10-04 16:19:13

标签: python sockets flask

嗨,我需要在flask应用程序上显示已连接客户端的总数,我编写此代码来检查已连接和已断开连接。

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)

然后我渲染这样的模板

return render_template_string(TABLE_TEMPLATE, data=data, clients=len(clients))

在html部分中,我这样称呼

<h1>{{ clients }} </h1>

但是在网页上,即使客户端已连接,它也会持续显示0,我从客户端获得输出并且连接了它,它应该显示1 2取决于连接的客户端数。即使我打印此打印文件(len(clients)),它也会返回0。甚至我的客户端都已连接,我得到了输出。

enter image description here

这是我更新的代码

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)

客户端:

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)
        

1 个答案:

答案 0 :(得分:0)

在阅读了socket.io文档之后,我设法在您的代码中发现了问题。

本身不是问题,但是对于此用例而言,增加/减少int计数器绰绰有余。其次,您不必将该计数器传递给render_template调用,因为您基本上是在conenct事件有机会触发之前传递用户计数。您应该发出一条消息(在本示例中为users主题),该消息将通知您的页面某些更改:

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)

此外,您没有在模板中打开与套接字的连接,这使您可以收听socketio装饰器发出的消息并更新所有连接的客户端。您还需要编写一些JavaScript,以指定用户每次连接/断开连接时都需要更新计数器。

<!-- 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 -->

话虽如此,您不需要在您的render_template调用中传递计数器值。 另外,从flask-socketio docs开始,通过以下方式启动您的应用似乎是一个好习惯:

if __name__ == "__main__":
    socketio.run(app)

Here链接到您示例的编辑版本。