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

Java持续存活进程问题:CMD命令执行类单次迭代后进程终止

问题分析与修复方案

问题根源

  1. 输入流被意外关闭:每次循环里用try-with-resources创建PrintWriter,这个语法会自动关闭关联的Process.getOutputStream()。CMD进程一旦检测到标准输入流关闭,就会直接终止,导致后续命令无法执行。
  2. 输出读取逻辑缺陷:Handle.getInputStream().read()会读取单个字节,若输出为空或流结束返回-1,会跳过输出读取;且每次创建新Scanner读取输出,可能遗漏未读取的缓存数据。

修复后的代码

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

class CommandLine {
    Process handle;
    PrintWriter stdin;
    Scanner commandScanner;
    Socket socket;

    public CommandLine(Socket socket) throws IOException {
        this.socket = socket;
    }

    public void executeCommand() {
        try {
            commandScanner = new Scanner(socket.getInputStream());
            // 启动CMD进程,重定向错误流到输出流
            handle = new ProcessBuilder("cmd.exe").redirectErrorStream(true).start();
            
            // 初始化标准输入流,放在循环外避免重复关闭
            stdin = new PrintWriter(handle.getOutputStream(), true);
            
            // 启动独立线程处理CMD输出,避免阻塞主线程
            new Thread(() -> {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(handle.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
            
            // 持续读取socket传来的命令并执行
            while (commandScanner.hasNextLine()) {
                String command = commandScanner.nextLine();
                stdin.println(command); // 自动flush(因为初始化时设置了autoFlush为true)
            }
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 资源清理
            if (stdin != null) stdin.close();
            if (handle != null) handle.destroy();
            try {
                if (socket != null) socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

关键修改说明

  • 避免输入流关闭:将PrintWriter初始化移到循环外部,不再用try-with-resources,而是在finally块统一关闭,保证CMD进程的输入流持续开放。
  • 异步处理输出:用单独线程读取CMD的输出,主线程专注于读取命令,避免因输出阻塞导致命令无法及时处理。
  • 优化输出读取:使用BufferedReader逐行读取输出,比Scanner更高效,且能保证读取所有输出内容。
  • 自动刷新输出:初始化PrintWriter时设置autoFlush=true,调用println会自动刷新,无需手动调用flush()。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 19:20:17