Как заставить apache SshClient понять, что удаленный конец отключен? - PullRequest
0 голосов
/ 19 февраля 2020

Я смотрю библиотеку apache sshd для создания клиента S SH (класс SshClient). Клиент использует канал подсистемы для ввода-вывода, так как я работаю с netconf, а не cli. Я инициирую такой канал

ClientChannel channel = session.createSubsystemChannel("netconf");

Однако по умолчанию этот канал подсистемы не понимает, подключен ли удаленный сеанс. Предполагается, что сессия жива и безмолвна. Состояние не изменится и для неудачных команд (что странно, так как вы получили бы таймаут TCP при отправке данных в первую очередь, но, возможно, он просто будет считать, что соединение дрянное, пока не получит RST).

2020-02-19T07:49:04,077 INFO   session state is [AUTHED]
2020-02-19T07:49:04,077 INFO   channel state is [OPENED]

Чтобы решить эту проблему, я добавил s sh heartbeat, который будет посылать SSH_MSG_IGNORE время от времени,

SshClient client = SshClient.setUpDefaultClient();
client.setSessionHeartbeat(SessionHeartbeatController.HeartbeatType.IGNORE, TimeUnit.MILLISECONDS, 1000);

Это частично решает мою проблему, так как я получаю Время ожидания семафора истекло. через 20 секунд.

2020-02-19T07:49:04,063 WARN   exceptionCaught(ClientSessionImpl[root@/147.214.81.124:830])[state=Opened] IOException: The semaphore timeout period has expired.
2020-02-19T07:49:04,077 INFO   session state is [AUTHED]
2020-02-19T07:49:04,077 INFO   channel state is [CLOSED, OPENED]

Однако это слишком долго, поэтому я хочу получить более быструю обратную связь, если канал / сеанс отключился. Это необходимо, поскольку перезапуск машины является операцией netconf, а также может быть выполнен другими способами. Затем необходимо восстановить соединение (в пределах c).

Кто-нибудь знает, как решить эту проблему? Мой пример кода приведен ниже.

BR
Patrik

SshClient client = SshClient.setUpDefaultClient();
client.setSessionHeartbeat(SessionHeartbeatController.HeartbeatType.IGNORE, TimeUnit.MILLISECONDS, 1000);
client.start();
try {
    ConnectFuture connect = client.connect("user", "secret", 830);
    try {
        connect.verify(5000);
    } catch (Exception e) {
        LOGGER.error("Exception occured: ", e);
        LOGGER.error("Cause=" + e.getCause());
        exit(1); // Just to terminate the app nicer. Maybe not ideal, but good enough for this demo.
    }
    ClientSession session = connect.getSession();
    session.addPasswordIdentity("secret");
    session.auth().verify(5000);
    ClientChannel channel = session.createSubsystemChannel("netconf");
    channel.setStreaming(ClientChannel.Streaming.Async);
    channel.open().verify(2000);
//    read(channel); // If you want to read NETCONF <hello/> message
    LOGGER.info("Wait for close");
    channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED, ClientChannelEvent.TIMEOUT), 0L);
//Terminate remote system, from the remote system here.
    LOGGER.info("session state is " + session.getSessionState());
    LOGGER.info("channel state is " + channel.getChannelState());
    LOGGER.info("closed now");
} catch (IOException e) {
    e.printStackTrace();
}
client.stop();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...