BufferedReader и JSch
У меня возникла проблема при работе через ssh с помощью Jsch. Чтение из канала зависало на получении данных и пользователь не мог это прервать.
Сначала программа выглядела так:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package ru.yamakarov;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
public class JschReader {
public static void main(String[] args) throws JSchException, IOException, InterruptedException {
JSch jsch = new JSch();
jsch.addIdentity(JschConstants.PRV_KEY);
Session session = jsch.getSession(
JschConstants.USER_NAME, JschConstants.HOST);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(5000);
Channel channel = session.openChannel("exec");
((ChannelExec) channel).setCommand("./my-command");
BufferedReader in = new BufferedReader(new InputStreamReader(channel.getInputStream()));
channel.connect();
String s;
while ((s = in.readLine()) != null) {
System.out.println(s);
}
channel.disconnect();
session.disconnect();
}
}
Она вызывала скрипт my-command:
echo 'Doing something long.'
sleep 10
echo 'Done something long.'
И все было хорошо:
Doing something long.
Done something long.
Process finished with exit code 0
Но потом my-command поменяли:
echo -n 'Doing something long.'
sleep 10
echo
echo 'Done something long.'
И программа стала зависать на:
s = in.readLine()
Так как перевод строки стал приходить после ожидания. Такое поведение меня не устраивало и я добавил in.ready()
while (in.ready() && (s = in.readLine()) != null) {
System.out.println(s);
}
Программа перестала дожидаться вывода и пришлось обернуть чтение в цикл:
while (true) {
while (in.ready() && (s = in.readLine()) != null) {
System.out.println(s);
}
if (!channel.isClosed()) {
Thread.sleep(100);
} else {
break;
}
}
Но меня этот вариант не устраивал, потому что функция висела на in.readLine() пока не заканчивался sleep. Все дело в том, что in.ready() говорит, что будет считан следующий символ, но ничего не говорит про следующую линию.
Я решил выводить все по одному символу:
int ch;
while (true) {
while (in.ready() && (ch = in.read()) != -1) {
System.out.print((char) ch);
}
if (!channel.isClosed()) {
Thread.sleep(100);
} else {
break;
}
}
И тогда все заработало.