Статьи

Общие VFS, SSHJ и JSch в сравнении

Несколько недель назад я оценил некоторые библиотеки SSH для Java. Основными требованиями к ним являются передача файлов и файловые операции на удаленной машине. Следовательно, существует сетевой протокол, основанный на SSH, SSH File Transfer Protocol (или SFTP). Поэтому мне нужна была библиотека SSH, которая поддерживает SFTP.

Исследования показывают, что он выходит из многих библиотек SSH для Java. Я уменьшаю количество библиотек до трех для сравнения. Я выбираю JSch, SSHJ и Apache Commons VFS для более глубокого изучения. Все они поддерживают SFTP. JSch кажется стандартом де-факто для Java. SSHJ — более новая библиотека. Его цель — иметь понятный Java API для SSH. Под капотом используется Apache SSHD. Цель Commons VFS — иметь понятный API для виртуальных файловых систем, а SFTP является одним из поддерживаемых протоколов. Под капотом он использует JSch для протокола SFTP. Библиотеки должны соответствовать следующим требованиям:

  • аутентификация клиента по паролю
  • аутентификация клиента через открытый ключ
  • проверка подлинности сервера
  • загружать файлы с локального хоста через SFTP
  • скачивать файлы на локальный хост через SFTP
  • файловые операции на удаленном хосте, такие как перемещение, удаление, список всех дочерних элементов данной папки (фильтрация по типу, например, файл или папка) по SFTP
  • выполнять простые команды оболочки

Давайте глубже рассмотрим, как три библиотеки соответствуют требованиям.

Аутентификация клиента

Все три библиотеки поддерживают оба обязательных метода аутентификации. SSHJ имеет самый понятный API для аутентификации ( SSHClient.authUserPass (), SSHClient.authUserPublicKey () ).

1
2
3
4
5
6
7
8
SSHClient sshClient= new SSHClient();
sshClient.connect(host);
 
// only for public key authentication
sshClient.authPublickey("user", "location to private key file");
 
// only for password authentication
sshClient.authPassword("user", "password");

В Commons VFS конфигурация аутентификации зависит от того, какой тип аутентификации следует использовать. Для аутентификации с открытым ключом закрытый ключ должен быть установлен в FileSystemOption, а имя пользователя является частью URL-адреса соединения. Для аутентификации по паролю имя пользователя и пароль являются частью URL-адреса соединения.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
StandardFileSystemManager fileSystemManager = new StandardFileSystemManager();
fileSystemManager.init();
 
// only for public key authentication
SftpFileSystemConfigBuilder sftpConfigBuilder = SftpFileSystemConfigBuilder.getInstance();
FileSystemOptions opts = new FileSystemOptions();
sftpConfigBuilder.setIdentities(opts, new File[]{privateKey.toFile()});
String connectionUrl = String.format("sftp://%s@%s", user, host);
 
// only for password authentication
String connectionUrl = String.format("sftp://%s:%s@%s", user, password, host);
 
// Connection set-up
FileObject remoteRootDirectory = fileSystemManager.resolveFile(connectionUrl, connectionOptions);

Конфигурация аутентификации в JSch похожа на Commons VFS. Это зависит от того, какой тип аутентификации следует использовать. Закрытый ключ для аутентификации с открытым ключом должен быть настроен в объекте JSch, а пароль для аутентификации по паролю должен быть установлен в объекте Session . Для обоих имя пользователя устанавливается, когда объект JSch получает объект Session .

01
02
03
04
05
06
07
08
09
10
11
JSch sshClient = new JSch();
 
// only for public key authentication
sshClient.addIdentity("location to private key file");
 
session = sshClient.getSession(user, host);
 
// only for password authentication
session.setPassword(password);
 
session.connect();

Аутентификация сервера

Все три библиотеки поддерживают аутентификацию сервера. В SSHJ аутентификация сервера может быть включена с помощью SSHClient.loadKnownHost . Можно добавить собственное местоположение файла known_host или использовать местоположение по умолчанию, которое зависит от используемой платформы.

1
2
3
SSHClient sshClient = new SSHClient();
sshClient.loadKnownHosts(); // or sshClient.loadKnownHosts(knownHosts.toFile());
sshClient.connect(host);

В Commons VFS конфигурация аутентификации сервера также является частью FileSystemOption, как аутентификация с открытым ключом. Там можно указать местоположение файла known_hosts .

1
2
3
SftpFileSystemConfigBuilder sftpConfigBuilder = SftpFileSystemConfigBuilder.getInstance();
FileSystemOptions opts = new FileSystemOptions();
sftpConfigBuilder.setKnownHosts(opts, new File("location of the known_hosts file"));

В JSch существует две возможности настроить аутентификацию сервера. Одной из возможностей является использование OpenSSHConfig (см. Пример JSch для OpenSSHConfig ). Другая возможность проще. Расположение файла known_hosts можно указать непосредственно в объекте JSch .

1
2
JSch sshClient = new JSch();
sshClient.setKnownHosts("location of known-hosts file");

Загрузить / скачать файлы через SFTP

Все три библиотеки поддерживают загрузку и загрузку файлов через SFTP. SSHJ имеет очень четкий API для этих операций. Объект SSHClient создает объект SFTPClient . Этот объект отвечает за загрузку ( SFTPClient . Put ) и за загрузку ( SFTPClient . Get ).

1
2
3
4
5
6
7
8
9
SSHClient sshClient = new SSHClient();
// ... connection
 
try (SFTPClient sftpClient = sshClient.newSFTPClient()) {
  // download
  sftpClient.get(remotePath, new FileSystemFile(local.toFile()));
  // upload
  sftpClient.put(new FileSystemFile(local.toFile()), remotePath);
}

В Commons VFS загрузка и выгрузка файлов абстрагируется как операция в файловой системе. Таким образом, оба представлены методом copyFrom объекта FileObject . Загрузка — это операция copyFrom для объекта RemoteFile, а загрузка — это операция copyFrom для LocalFile.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
StandardFileSystemManager fileSystemManager = new StandardFileSystemManager();
// ... configuration
remoteRootDirectory = fileSystemManager.resolveFile(connectionUrl, connectionOptions);
 
LocalFile localFileObject = (LocalFile) fileSystemManager.resolveFile(local.toUri().toString());
FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath);
try {
  // download
  localFileObject.copyFrom(remoteFileObject, new AllFileSelector());
 
  // upload
  remoteFileObject.copyFrom(localFileObject, new AllFileSelector());
} finally {
  localFileObject.close();
  remoteFileObject.close();
}

JSch также поддерживает SFTPClient. В JSch это называется ChannelSFTP . Он имеет два метода для загрузки ( ChannelSFTP.get ) и загрузки ( ChannelSFTP.put ).

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
// here: creation and configuration of session
 
ChannelSftp sftpChannel = null;
try {
  sftpChannel = (ChannelSftp) session.openChannel("sftp");
  sftpChannel.connect();
 
  // download
  InputStream inputStream = sftpChannel.get(remotePath);
  Files.copy(inputStream, localPath);
 
  // upload
  OutputStream outputStream = sftpChannel.put(remotePath);
  Files.copy(locaPathl, outputStream);
} catch (SftpException | JSchException ex) {
  throw new IOException(ex);
} finally {
  if (sftpChannel != null) {
    sftpChannel.disconnect();
  }
}

Выполнить команды оболочки

Только Commons VFS не поддерживает выполнение простых команд оболочки. В SSHJ это двухлинейный. SshClient запускает новый объект Session . Этот объект выполняет команду оболочки. Это очень интуитивно понятно.

1
2
3
4
5
// creation and configuration of sshClient
 
try (Session session = sshClient.startSession()) {
  session.exec("ls");
}

В Jsch ChannelExec отвечает за выполнение команд оболочки через SSH. Сначала команда устанавливается в канале, а затем канал должен быть запущен. Это не так интуитивно понятно, как в SSHJ.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
// here: creation and configuration of session object
 
ChannelExec execChannel = null;
try {
  execChannel = (ChannelExec) session.openChannel("exec");
  execChannel.connect();
  execChannel.setCommand(command);
  execChannel.start();
} catch (JSchException ex) {
  throw new IOException(ex);
} finally {
  if (execChannel != null) {
    execChannel.disconnect();
  }
}

Файловые операции на удаленных хостах

Все библиотеки поддерживают более или менее идеальные файловые операции через SFTP на удаленных машинах. В SSHJ SFTPClient есть также методы для файловых операций. Имена методов совпадают с файловыми операциями в системе Linux. Следующий фрагмент кода показывает, как удалить файл.

1
2
3
4
5
//here: creation and configuration of sshClient
 
try (SFTPClient sftpClient = sshClient.newSFTPClient()) {
  sftpClient.rm(remotePath);
}

Основная функциональность Commons VFS — файловые операции. Использование требует привыкания. Файловый объект должен быть разрешен, и над ним могут быть выполнены файловые операции.

1
2
3
4
5
6
7
8
// here: creation and configuration of remoteRootDirectory
 
FileObject remoteFileObject = remoteRootDirectory.resolveFile(remotePath);
try {
  remoteFileObject.delete();
} finally {
  remoteFileObject.close();
}

SFTPClient ChannelSFTP от JSch также имеет метод для файловых операций. Этот канал поддерживает в основном файловые операции. Например, операция копирования файла на удаленной машине должна выполняться с помощью простых команд оболочки через ChannelExec .

01
02
03
04
05
06
07
08
09
10
11
12
13
// here: creation and configuration of session
ChannelSftp sftpChannel = null;
try {
  sftpChannel = (ChannelSftp) session.openChannel("sftp");
  sftpChannel.connect();
  sftpChannel.rm(remotePath);
} catch (SftpException | JSchException ex) {
  throw new IOException(ex);
} finally {
  if (sftpChannel != null) {
    sftpChannel.disconnect();
  }
}

Вывод

После этого сравнения у меня есть два фаворита, SSHJ и Commons VFS. У SSHJ очень четкий API, и я бы выбрал его, если мне нужен обычный SSH-клиент или достаточно поддержки файловых операций через SFTP. Я бы выбрал Commons VFS, если у меня есть файловая операция по многим протоколам файловой системы или общий SSH-клиент не нужен. В случае, когда мне нужны оба, я мог бы использовать JSch напрямую для выполнения команд через SSH. API Commons VFS требует привыкания. Но после понимания концепции, лежащей в основе, использование API становится простым.

Целые примеры исходного кода этого сравнения размещены на Github .

Полезные ссылки

  1. Домашняя страница SSHJ
  2. JSch домашняя страница
  3. Домашняя страница Commons-vfs
  4. Страница Википедии о SFTP
  5. Домашняя страница SSHD
  6. Исходный код этого сравнения на Github
Ссылка: Сравнение VFS, SSHJ и JSch в сравнении с нашей партнером по JCG Сандрой Парсик в блоге SKM IT WORLD .