You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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>

关键说明

  1. 后端:使用threading启动后台线程执行任务,避免阻塞Flask主线程;通过subprocess.Popen实时读取脚本输出,解析后用socket_.emit推送状态到前端。
  2. 前端:移除表单的自动提交逻辑,改用SocketIO发送任务请求;监听ticket_status事件,实时更新按钮文本;禁用按钮防止重复提交,任务完成后恢复按钮状态。
  3. 输出解析:需要根据你的process.py实际输出格式调整状态解析逻辑,确保能正确提取数据包数量等信息。

内容的提问来源于stack exchange,提问作者shreesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 14:10:22