问题现象:
session = conn.openSession(); // 打开一个会话
session.execCommand(cmd, DEFAULT_CHAR_SET); // 执行命令
StringBuilder builder = new StringBuilder();
try {
br = new BufferedReader(new InputStreamReader(new StreamGobbler(session.getStdout()), "UTF-8"));
String line;
// 启动线程读取 error,防止 hang 住
//printStream(session.getStderr(), printWriterList);
while ((line = br.readLine()) != null) {
// writeLog(printWriterList, line);
//打印日志
if (line.contains("2 dependencies")) {
System.out.println("dead loop");
}
builder.append(line).append("\n");
}
session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
// 获取执行的退出码
Integer status = session.getExitStatus();
} catch (IOException e) {
System.err.println("解析脚本出错:" + e.getMessage());
e.printStackTrace();
} finally {
if (session != null) {
session.close();
}
}
上方代码 printStream(session.getStderr(), printWriterList); 注释掉了,当执行完命令后,在 while 循环中,会发生 readLine() hang 住的现象。
打开注释之后,先把 Stderr 流打印出来,就可以正常运行。
private static void printStream(InputStream inputStream, List<PrintWriter> printWriterList) {
new Thread(new Runnable() {
@Override
public void run() {
InputStreamReader isr = null;
BufferedReader br = null;
try {
isr = new InputStreamReader(inputStream, "utf8");
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
writeLog(printWriterList, line);
// System.out.println(outtag + "" + line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (br != null) {
br.close();
}
if (isr != null) {
isr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
个人猜想:
ganymed-ssh2 库在建立ssh连接后,会创建一个 buffer 缓冲来存放服务器返回的数据流,包含 stdOutStream 和 stdErrStream 流,这两个 inputStream 是存放在同一个 buffer 中,当循环读取 stdOutStream 中的内容时,读完标准输出流之后,遇到标准错误流,由于 buffer 中同时存在 stdErrStream,此时由于标准错误流一直没有被读取,所以度标准输出流的 readLine() 就被hang 住。
主要原因:
stdOutStream 和 stdErrStream 流 共用同一个 buffer,当 errStream 写满了 buffer 之后,outStream 就无法再写入内容,造成 outStream hang 住。