如何通过Flask-SocketIO在执行Ping任务时实时更新HTML按钮文本
实现Flask-SocketIO实时推送任务状态更新按钮文本
完全可行,通过Flask-SocketIO可以实现服务器主动推送真实的任务执行状态到前端,替代原来固定时间间隔的文本更新,让用户直观看到任务的实时进度。以下是具体的修改方案:
后端代码修改
核心改动是将同步的任务执行改为后台线程处理,同时实时捕获任务输出并通过SocketIO推送状态:
from flask import Flask, render_template, request, session import subprocess from flask_socketio import SocketIO import threading async_mode = None app = Flask(__name__) # 允许跨域(如果前端和后端不在同一域名下) socket_ = SocketIO(app, async_mode=async_mode, cors_allowed_origins="*") app.secret_key = "sdfwq34qweds" @app.route('/') @app.route('/home') def home(): return render_template('home.html', sync_mode=socket_.async_mode) @app.route('/about') def about(): return render_template('about.html') @app.route('/contact') def contact(): return render_template('contact.html') # 后台任务函数:执行脚本并推送实时状态 def execute_task(ip, ticket, starttime, endtime): # 推送初始状态 socket_.emit('task_status', {'message': f'processing...正在向{ip}发送请求..'}) # 执行外部脚本,实时捕获输出 cmd = f"/usr/bin/python3.8 /u0/sn/dev_scripts/process.py -i {ip} -t {ticket} -f {starttime} -e {endtime}" # 以文本模式读取输出,同时捕获标准输出和错误 process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) received_packets = 0 # 逐行读取输出 for line in iter(process.stdout.readline, ''): if line: line_content = line.strip() # 根据实际脚本输出解析数据包数量(这里需要适配你的process.py输出格式) if "已接收" in line_content: # 示例解析逻辑,根据实际输出调整 received_packets = line_content.split('已接收')[1].strip().split()[0] socket_.emit('task_status', {'message': f'processing...正在向{ip}发送请求..已接收{received_packets}个数据包'}) else: # 推送其他中间状态 socket_.emit('task_status', {'message': f'processing...{line_content}'}) # 等待任务结束 process.wait() # 推送完成状态 socket_.emit('task_status', {'message': f'任务完成!共接收{received_packets}个数据包'}) # SocketIO事件:接收前端的任务启动请求 @socket_.on('start_task') def handle_start_task(data): ip = data['ip'] ticket = data['tic'] starttime = data['stime'] endtime = data['etime'] # 保存数据到session(如果后续需要使用) session["ip2"] = ip session["ticket2"] = ticket session["starttime2"] = starttime session["endtime2"] = endtime # 启动后台线程执行任务,避免阻塞主线程 threading.Thread(target=execute_task, args=(ip, ticket, starttime, endtime)).start() if __name__ == '__main__': socket_.run(app, host='0.0.0.0', port=8080, debug=True)
前端代码修改
核心改动是改用SocketIO发送任务请求,监听服务器推送的状态并实时更新按钮文本:
{% extends 'architecture.html' %} {% block title %} <title>LaunchPad</title> {% endblock %} <body> {% block head %} <h1 class="display-1" style="text-align: center;">PING TESTER</h1> <blockquote class="blockquote"> </blockquote> <figure style="text-align:center;"> </figure> {% endblock %} {% block content %} <!-- 移除表单的action和method,避免页面刷新 --> <form id="nexus"> <div class="form-floating mb-3 animate__animated animate__fadeInDown"> <!-- 把type改为text,IP不是整数类型 --> <input type="text" name="ip" id='ipadd' placeholder="8.8.8.8" class="form-control" > <label for="ip">Machine IP</label> </div> <!-- 以下日期选择器部分保持原有逻辑不变 --> <div class="form-group form-floating mb-3 animate__animated animate__fadeInDown"> <input class="form-control input-lg" type="datetimepicker" required="required" placeholder="YYYY/MM/dd-hh:mm" id="fromdatetime" name="stime" autocomplete="off"> <label for="stime">Start Time</label> <script src="../static/js/flatpickr"></script> <script> $('#fromdatetime').flatpickr({ enableTime: true, time_24hr: true, dateFormat: "d/m/Y/H:i", allowInput: true, minuteIncrement:30, }); </script> </div> <div class="form-group form-floating mb-3 animate__animated animate__fadeInDown"> <input class="form-control input-lg" type="datetimepicker" required="required" placeholder="YYYY/MM/dd-hh:mm" title="Ending Time-frame" id="endtime" name="etime" autocomplete="off"> <label for="etime">End Time</label> <script type='text/JavaScript'> $('#endtime').flatpickr({ enableTime: true, showAlways: true, time_24hr: true, dateFormat: "d/m/Y/H:i", allowInput: true, minuteIncrement:30, }); </script> </div> <!-- 把submit按钮改为普通button,避免表单提交刷新 --> <input id="submit_lead" type="button" class="btn inputdisabled btn-dark animate__animated animate__fadeInDown" value="Execute ..."> <!-- 引入SocketIO客户端库 --> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script> <script> $(document).ready(function(e) { // 初始化SocketIO连接 var socket = io(); // 按钮点击事件:发送任务请求 $('#submit_lead').click(function() { var btn = $(this); // 禁用按钮防止重复提交 btn.prop('disabled', true); btn.val("正在初始化任务..."); // 收集表单数据 var formData = { ip: $('#ipadd').val(), tic: "", // 原表单未看到ticket输入框,根据实际情况补充 stime: $('#fromdatetime').val(), etime: $('#endtime').val() }; // 通过SocketIO发送任务请求 socket.emit('start_task', formData); }); // 监听服务器推送的状态更新 socket.on('task_status', function(data) { $('#submit_lead').val(data.message); // 任务完成后恢复按钮可点击状态 if (data.message.includes('任务完成')) { $('#submit_lead').prop('disabled', false); } }); }); </script> </form> {% endblock %} </body>
关键说明
- 后端:使用
threading启动后台线程执行任务,避免阻塞Flask主线程;通过subprocess.Popen实时读取脚本输出,解析后用socket_.emit推送状态到前端。 - 前端:移除表单的自动提交逻辑,改用SocketIO发送任务请求;监听
ticket_status事件,实时更新按钮文本;禁用按钮防止重复提交,任务完成后恢复按钮状态。 - 输出解析:需要根据你的
process.py实际输出格式调整状态解析逻辑,确保能正确提取数据包数量等信息。
内容的提问来源于stack exchange,提问作者shreesh
相关产品推荐
相关产品推荐

