父子进程间TCP Socket通信数秒后阻塞问题求助
父子进程Socket阻塞问题原因解析
核心原因:子进程IO缓冲区未被父进程读取导致阻塞
当直接用Runtime.getRuntime().exec()启动子进程时,子进程的标准输入(stdin)、标准输出(stdout)、标准错误(stderr)会与父进程保持管道连接。Windows系统下这类管道的缓冲区容量有限(通常仅几KB),如果子进程向stdout/stderr输出内容,而父进程未及时读取这些缓冲区,缓冲区被填满后,操作系统会直接挂起子进程,使其无法继续执行后续代码(包括Socket的write操作)。这就导致Agent卡在socket.write调用上,父进程因等待不到Agent的响应,也会阻塞在socket.read操作中。为什么
cmd /c start方式运行正常?
使用cmd /c start启动安装程序时,start命令会创建一个完全独立的新进程,该进程的IO流会绑定到新的控制台窗口(或后台独立会话),与父进程的管道完全断开。因此子进程的输出缓冲区不会因父进程未读取而被填满,子进程可以持续正常运行,Socket通信流程也就不会中断。
参考案例(原问题翻译):C++ TCP Socket通信初期完全正常,但几秒后出现异常,无法接收新数据,read()和recv()调用持续阻塞。该问题的核心原因同样是子进程IO缓冲区未被父进程处理,导致子进程挂起,进而中断Socket通信流程。
- 解决方法
- 在父进程中启动独立线程,持续读取子进程的
getInputStream()和getErrorStream(),避免缓冲区被填满:
Process process = Runtime.getRuntime().exec(new String[] { "installer.exe", "-J-javaagent:myagent.jar" }); // 读取子进程标准输出 new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { // 可输出到日志或直接忽略 System.out.println("子进程输出:" + line); } } catch (IOException e) { e.printStackTrace(); } }).start(); // 读取子进程标准错误 new Thread(() -> { try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { String line; while ((line = reader.readLine()) != null) { System.err.println("子进程错误输出:" + line); } } catch (IOException e) { e.printStackTrace(); } }).start();- 如果不需要子进程的输出内容,可将其stdout/stderr重定向到Windows的
NUL设备,避免缓冲区积累:
Process process = new ProcessBuilder("installer.exe", "-J-javaagent:myagent.jar") .redirectOutput(new File("NUL")) .redirectError(new File("NUL")) .start(); - 在父进程中启动独立线程,持续读取子进程的
内容的提问来源于stack exchange,提问作者Reto Höhener
相关产品推荐
相关产品推荐

