Используются: Maven 3, IntelliJ Idea 12 Ultimate, JSch 0.1.50, SSH.
<dependencies>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.50</version>
</dependency>
</dependencies>
Давайте создадим класс ru.blogspot.developer.remarks.SshManager. В него добавим статические поля, чтобы в любой момент эти параметры легко было найти и изменить.
private static final int SSH_PORT = 22;
private static final int CONNECTION_TIMEOUT = 10000;
private static final int BUFFER_SIZE = 1024;
SSH_PORT - это порт для SSH подключения. На любом сервере обычно это 22-ой порт. Однако может быть и другой. CONNECTION_TIMEOUT - время, в течение которого мы будем ожидать ответа от удалённого сервера. Указывается в миллисекундах. В данном случае у нас установлено 10 секунд. BUFFER_SIZE - размер буфера для приёма ответа от сервера.
Следующие три параметра нужны для доступа к удалённом хосту. Разумеется, у вас они будут другими.
private static final String HOSTNAME = "192.168.1.2";
private static final String USERNAME = "admin";
private static final String PASSWORD = "123456";
Далее статический метод main, создающий экземпляр нашего класса и вызывающий подключение к хосту. Затем мы выводим полученные строки на экран.
public static void main(String[] args) {
SshManager manager = new SshManager();
List<String> lines = manager.connectAndExecuteListCommand(HOSTNAME, USERNAME, PASSWORD);
System.out.println(lines);
}
Основной метод, в котором реализуется вся логика работы нашего приложения:
public List<String> connectAndExecuteListCommand(String host, String username, String password) {
List<String> lines = new ArrayList<String>();
try {
String command = "ls -1\n";
Session session = initSession(host, username, password);
Channel channel = initChannel(command, session);
InputStream in = channel.getInputStream();
channel.connect();
String dataFromChannel = getDataFromChannel(channel, in);
lines.addAll(Arrays.asList(dataFromChannel.split("\n")));
channel.disconnect();
session.disconnect();
} catch (Exception e) {
System.out.println(e);
}
return lines;
}
В качестве примера мы подключимся к хосту и выполним там команду ls -l (вывести все файлы и папки в текущей директории в один столбец). Результат выполнения мы получим в виде набора строк, по одному элементу в каждой строке. Разумеется, вы можете выполнить абсолютно любую консольную команду, какую вы захотите.
Далее идут вспомогательные методы. Метод создания сессии:
private Session initSession(String host, String username, String password) throws JSchException {
JSch jsch = new JSch();
Session session = jsch.getSession(username, host, SSH_PORT);
session.setPassword(password);
UserInfo userInfo = new MyUserInfo();
session.setUserInfo(userInfo);
session.setConfig("StrictHostKeyChecking", "no");
session.connect(CONNECTION_TIMEOUT);
return session;
}
Здесь нам потребуется создать вспомогательный класс MyUserInfo, реализующий интерфейс UserInfo.
public class MyUserInfo implements UserInfo {
private String password;
public void showMessage(String message) {
System.out.println(message);
}
public boolean promptYesNo(String message) {
System.out.println(message);
return true;
}
@Override
public String getPassphrase() {
return null;
}
@Override
public String getPassword() {
return this.password;
}
@Override
public boolean promptPassphrase(String arg0) {
System.out.println(arg0);
return true;
}
@Override
public boolean promptPassword(String arg0) {
System.out.println(arg0);
this.password = arg0;
return true;
}
}
По сути это заранее определённый набор ответов пользователя на запросы системы. Например, при запросе пароля будет автоматически введён пароль, который здесь указан. При любом вопросе с вариантами ответа "Да/Нет" всегда будет подставляться ответ "Да". Такой класс позволяет полностью автоматизировать взаимодействие по SSH.
Вернёмся к нашему основному классу. Следующий вспомогательный метод:
private Channel initChannel(String commands, Session session) throws JSchException {
Channel channel = session.openChannel("exec");
ChannelExec channelExec = (ChannelExec) channel;
channelExec.setCommand(commands);
channelExec.setInputStream(null);
channelExec.setErrStream(System.err);
return channel;
}
Здесь создаётся канал для выполнения команд, о чём свидетельствует параметр "exec". Устанавливаем строку с командами, которые мы хотим выполнить. Если вы хотите выполнить сразу несколько команд, просто разделите их символом перевода строки, как и в обычной командной оболочке. Входной поток устанавливаем в null (мы его не будем использовать). Поток ошибок устанавливаем, соответственно, в System.err.
Метод для получения данных из канала (т.е. ответа от хоста).
private String getDataFromChannel(Channel channel, InputStream in)
throws IOException {
StringBuilder result = new StringBuilder();
byte[] tmp = new byte[BUFFER_SIZE];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, BUFFER_SIZE);
if (i < 0) {
break;
}
result.append(new String(tmp, 0, i));
}
if (channel.isClosed()) {
int exitStatus = channel.getExitStatus();
System.out.println("exit-status: " + exitStatus);
break;
}
trySleep(1000);
}
return result.toString();
}
Здесь мы считываем данные в буфер указанного нами размера до тех пор, пока данные продолжают поступать. После закрытия канала получаем код статуса. Если всё прошло успешно, статус равен нулю. Пока канал не закрыт, ожидаем получения новых данных с интервалом в одну секунду.
Для этого используется ещё один простой метод:
private void trySleep(int sleepTimeInMilliseconds) {
try {
Thread.sleep(sleepTimeInMilliseconds);
} catch (Exception e) {
}
}
Всё, наш основной класс готов. Осталась одна маленькая деталь.
Нам нужно создать автономный исполняемый (runnable jar) файл, чтобы его легко можно было запускать прямо из командной строки вне какой-либо среды исполнения. Как это сделать, описано здесь.
Нам нужно создать автономный исполняемый (runnable jar) файл, чтобы его легко можно было запускать прямо из командной строки вне какой-либо среды исполнения. Как это сделать, описано здесь.
Теперь выполните в консоли команду java -jar target/ssh-example-1.0-SNAPSHOT-executable.jar, находясь при этом в директории вашего проекта. Если всё было сделано правильно, вы получите список файлов и каталогов в домашней директории на удалённом хосте.