У меня возникла проблема при работе через 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;
    }
}

И тогда все заработало.