Java持续存活进程问题:CMD命令执行类单次迭代后进程终止
问题分析与修复方案
问题根源
- 输入流被意外关闭:每次循环里用
try-with-resources创建PrintWriter,这个语法会自动关闭关联的Process.getOutputStream()。CMD进程一旦检测到标准输入流关闭,就会直接终止,导致后续命令无法执行。 - 输出读取逻辑缺陷:
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
相关产品推荐
相关产品推荐

