Я смотрю библиотеку 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();