Python 如何在flask中连接客户端

Python 如何在flask中连接客户端,python,sockets,flask,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='/') de

您好,我需要在我的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\u template\u string(TABLE\u template,data=data,clients=len(clients))

在html部分,我这样调用

{{clients}}

但在网页上,它一直显示
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)
在阅读了一些文档之后,我成功地发现了代码中的问题

这本身不是问题,但是对于这个用例,递增/递减
int
计数器就足够了。其次,您不必将该计数器传递给
render\u template
调用,因为您基本上是在
conenct
事件触发之前传递用户计数。您应该发出一条消息(在本例中带有
users
topic),通知您的页面发生了更改:

从烧瓶导入烧瓶,请求,呈现\u模板\u字符串
从flask_socketio导入socketio,发射
app=烧瓶(名称)
socketio=socketio(应用程序,日志=True)
客户端=0
@socketio.on(“connect”,namespace=“/”)
def connect():
#需要共享的全局变量
全球客户
客户端+=1
#每当有人连接时,发送一条包含用户计数的消息
emit(“users”,{“user_count”:clients},broadcast=True)
@socketio.on(“断开连接”,命名空间=“/”)
def disconnect():
全球客户
客户-=1
emit(“users”,{“user_count”:clients},broadcast=True)
此外,您没有在模板中打开到套接字的连接,这允许您侦听
socketio
装饰程序发出的消息,并更新所有连接的客户端。您还需要编写一点javascript来指定每当用户连接/断开连接时都需要更新计数器


$(文档).ready(函数(){
变量名称空间='/';
var socket=io.connect('http://'+document.domain+':'+location.port+名称空间);
//当新用户连接时更新计数器
socket.on('users',函数(users){
userCount=document.getElementById('user_counter');
userCount.innerHTML=users.user\u count;
});
});
也就是说,您不需要在
render\u模板调用中传递计数器值。
另外,从
flask socketio
,以以下方式启动应用程序似乎是一种良好的做法:

如果名称=“\uuuuu main\uuuuuuuu”:
socketio.run(应用程序)
指向示例的编辑版本的链接。

在阅读了一些文档后,我成功地发现了代码中的问题

这本身不是问题,但是对于这个用例,递增/递减
int
计数器就足够了。其次,您不必将该计数器传递给
render\u template
调用,因为您基本上是在
conenct
事件触发之前传递用户计数。您应该发出一条消息(在本例中带有
users
topic),通知您的页面发生了更改:

从烧瓶导入烧瓶,请求,呈现\u模板\u字符串
从flask_socketio导入socketio,发射
app=烧瓶(名称)
socketio=socketio(应用程序,日志=True)
客户端=0
@socketio.on(“connect”,namespace=“/”)
def connect():
#需要共享的全局变量
全球客户
客户端+=1
#每当有人连接时,发送一条包含用户计数的消息
emit(“users”,{“user_count”:clients},broadcast=True)
@socketio.on(“断开连接”,命名空间=“/”)
def disconnect():
全球客户
客户-=1
emit(“users”,{“user_count”:clients},broadcast=True)
此外,您没有在模板中打开到套接字的连接,这允许您侦听
socketio
装饰程序发出的消息,并更新所有连接的客户端。您还需要编写一点javascript来指定每当用户连接/断开连接时都需要更新计数器


$(文档).ready(函数(){
变量名称空间='/';
var socket=io.connect('http://'+document.domain+':'+location.port+名称空间);
//当新用户连接时更新计数器
socket.on('users',函数(users){
userCount=document.getElementById('user_counter');
userCount.innerHTML=users.user\u count;
});
});
也就是说,您不需要在
render\u模板调用中传递计数器值。
另外,从
flask socketio
,以以下方式启动应用程序似乎是一种良好的做法:

如果名称=“\uuuuu main\uuuuuuuu”:
socketio.run(应用程序)

指向示例的已编辑版本的链接。

在connect和disconnect事件中添加两个print语句,似乎socketio事件未正确触发。但是,不太确定是什么导致了问题……在connect和disconnect事件中添加了几个print语句,似乎socketio事件没有正确触发。虽然不太确定是什么导致了问题…您好,谢谢您,但是有一个问题,我在连接任何客户端之前运行您的代码,比如说1个客户端连接如果我刷新它增量2、3等等,甚至没有客户端连接,这对我来说很好,除了启动应用程序时不需要传递
threaded
参数。另外,不需要导入
打字。计数器,为什么要这样做?我改变了一切
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)