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

如何用Flask开发终端模拟器?实现D盘路径CMD命令运行需求

解决方案:Flask实现无弹窗的交互式CMD终端

1. 解决subprocess运行长驻进程的问题

之前用subprocess执行持续运行的命令报错,核心原因是阻塞式调用(如subprocess.run)导致请求超时,或未正确处理进程输出缓冲区。改用subprocess.Popen以非阻塞方式启动进程,同时设置参数避免弹出CMD窗口:

import subprocess
from flask import Flask, jsonify

app = Flask(__name__)
# 存储运行中的进程(演示用全局变量,生产环境建议用Redis/数据库管理)
running_processes = {}

def start_cmd_process(work_dir="D:\\"):
    # 配置启动参数,隐藏CMD窗口
    startup_info = subprocess.STARTUPINFO()
    startup_info.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # 启动CMD进程,绑定输入输出管道
    return subprocess.Popen(
        ["cmd.exe"],
        cwd=work_dir,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        text=True,
        bufsize=1,
        startupinfo=startup_info
    )

@app.route('/init-terminal', methods=['POST'])
def init_terminal():
    process = start_cmd_process()
    running_processes[process.pid] = process
    return jsonify({"pid": process.pid})

2. 实现交互式实时终端功能

要让网页和原生终端一样实时交互,用WebSocket实现双向通信(比长轮询更高效),依赖flask-socketio:

先安装依赖:

pip install flask-socketio

修改Flask代码添加WebSocket支持:

from flask_socketio import SocketIO, emit

app.config['SECRET_KEY'] = 'your-local-secret'
socketio = SocketIO(app, cors_allowed_origins="*")

def stream_process_output(process, client_sid):
    # 实时读取进程输出并推送到前端
    for line in iter(process.stdout.readline, ''):
        if line:
            socketio.emit('terminal_output', {"content": line.strip()}, room=client_sid)
    process.wait()
    del running_processes[process.pid]
    socketio.emit('terminal_closed', {"msg": "进程已退出"}, room=client_sid)

@socketio.on('start_terminal')
def handle_start_terminal():
    process = start_cmd_process("D:\\")
    running_processes[process.pid] = process
    # 启动后台线程处理输出,避免阻塞WebSocket事件循环
    socketio.start_background_task(stream_process_output, process, request.sid)
    emit('terminal_ready', {"pid": process.pid})

@socketio.on('send_command')
def handle_send_command(data):
    pid = data['pid']
    cmd = data['cmd'] + '\n'
    if pid in running_processes:
        process = running_processes[pid]
        process.stdin.write(cmd)
        process.stdin.flush()

3. 前端终端界面实现

用HTML+JS模拟原生CMD的外观和交互:

<!DOCTYPE html>
<html>
<head>
    <title>Flask CMD Terminal</title>
    <style>
        body {
            background: #000;
            color: #0f0;
            font-family: Consolas, monospace;
            padding: 15px;
            margin: 0;
        }
        #output-area {
            height: 450px;
            overflow-y: auto;
            margin-bottom: 10px;
            border-bottom: 1px solid #0f0;
            padding-bottom: 10px;
        }
        #cmd-input {
            width: 100%;
            background: #000;
            color: #0f0;
            border: none;
            font-family: Consolas, monospace;
            font-size: 16px;
            outline: none;
        }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
</head>
<body>
    <div id="output-area"></div>
    <input type="text" id="cmd-input" placeholder="输入命令...">

    <script>
        const socket = io();
        let currentPid = null;

        socket.on('connect', () => {
            socket.emit('start_terminal');
        });

        socket.on('terminal_ready', (res) => {
            currentPid = res.pid;
        });

        socket.on('terminal_output', (res) => {
            const outputDiv = document.getElementById('output-area');
            outputDiv.innerHTML += `<div>${res.content}</div>`;
            outputDiv.scrollTop = outputDiv.scrollHeight;
        });

        socket.on('terminal_closed', (res) => {
            const outputDiv = document.getElementById('output-area');
            outputDiv.innerHTML += `<div>${res.msg}</div>`;
            currentPid = null;
        });

        document.getElementById('cmd-input').addEventListener('keypress', (e) => {
            if (e.key === 'Enter' && currentPid) {
                const cmd = e.target.value;
                socket.emit('send_command', {pid: currentPid, cmd: cmd});
                e.target.value = '';
            }
        });
    </script>
</body>
</html>

关键注意事项

  • 进程管理:全局字典仅用于演示,生产环境需用进程管理器或持久化存储管理进程,避免内存泄漏。
  • 权限控制:确保Flask运行用户拥有D盘访问权限,以及执行目标命令的权限。
  • 安全风险:直接开放任意CMD命令执行存在极高安全隐患,生产环境必须添加命令白名单或严格的权限校验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:43:17