嗨,我需要在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
。甚至我的客户端都已连接,我得到了输出。
这是我更新的代码
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)
答案 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链接到您示例的编辑版本。