1. 概述
在现代软件开发和系统管理中,与远程服务器交互是常见需求。通过SSH客户端编程式交互服务器,可实现应用部署、配置管理、文件传输等操作。Java生态中常用的SSH客户端库包括JSch、Apache Mina SSHD和SSHJ。
本教程将演示如何使用这三个库与远程服务器交互,包括通过私钥建立连接并列出指定目录的所有文件。
2. 使用JSch库
JSch(Java Secure Channel)是SSH2的Java实现,提供连接SSH服务器的核心功能。
首先添加JSch依赖到pom.xml
:
<dependency>
<groupId>com.github.mwiede</groupId>
<artifactId>jsch</artifactId>
<version>0.2.18</version>
</dependency>
定义连接参数(实际使用时替换占位符):
private static final String HOST = "192.168.1.100";
private static final String USER = "admin";
private static final String PRIVATE_KEY = "/home/user/.ssh/id_rsa";
private static final int PORT = 22;
private static final String REMOTE_DIR = "/var/log";
初始化JSch并加载私钥:
JSch jsch = new JSch();
jsch.addIdentity(PRIVATE_KEY);
创建会话并连接(⚠️ 生产环境应启用主机密钥验证):
Session session = jsch.getSession(USER, HOST, PORT);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
Session对象用于创建SSH会话。为简化示例,我们禁用了严格的主机密钥检查。
接着在SSH连接上打开SFTP通道:
ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
channelSftp.connect();
ChannelSftp对象支持文件上传、下载、列表等操作。
2.1. 详细文件列表
通过SFTP通道获取远程目录文件列表:
Vector<ChannelSftp.LsEntry> files = channelSftp.ls(REMOTE_DIR);
for (ChannelSftp.LsEntry entry : files) {
LOGGER.info(entry.getLongname());
}
ls()
方法返回Vector<ChannelSftp.LsEntry>
集合,每个元素代表文件或目录。**getLongname()
返回包含权限、所有者、组、大小等详细信息的字符串**。
2.2. 仅文件名
若只需文件名,调用getFilename()
方法:
Vector<ChannelSftp.LsEntry> files = channelSftp.ls(REMOTE_DIR);
for (ChannelSftp.LsEntry entry : files) {
LOGGER.info(entry.getFilename());
}
操作完成后务必关闭连接(✅ 养成良好习惯):
channelSftp.disconnect();
session.disconnect();
3. 使用Apache Mina SSHD库
Apache Mina SSHD支持客户端和服务器端SSH协议实现。添加依赖:
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>2.13.1</version>
</dependency>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-sftp</artifactId>
<version>2.13.1</version>
</dependency>
初始化SSH客户端(使用try-with-resources自动管理资源):
try (SshClient client = SshClient.setUpDefaultClient()) {
client.start();
client.setServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE);
// ...
}
建立SSH连接并认证:
try (ClientSession session = client.connect(USER, HOST, PORT).verify(10000).getSession()) {
FileKeyPairProvider fileKeyPairProvider = new FileKeyPairProvider(Paths.get(privateKey));
Iterable<KeyPair> keyPairs = fileKeyPairProvider.loadKeys(null);
for (KeyPair keyPair : keyPairs) {
session.addPublicKeyIdentity(keyPair);
}
session.auth().verify(10000);
}
FileKeyPairProvider
加载私钥,由于示例私钥无密码,loadKeys()
参数传null。
3.1. 详细文件列表
创建SFTP客户端并读取目录:
SftpClientFactory factory = SftpClientFactory.instance();
try (SftpClient sftp = factory.createSftpClient(session)) {
Iterable<SftpClient.DirEntry> entriesIterable = sftp.readDir(REMOTE_DIR);
List<SftpClient.DirEntry> entries = StreamSupport.stream(entriesIterable.spliterator(), false)
.collect(Collectors.toList());
for (SftpClient.DirEntry entry : entries) {
LOGGER.info(entry.getLongFilename());
}
}
readDir()
返回Iterable<SftpClient.DirEntry>
,转换为List后遍历输出详细文件名。
3.2. 仅文件名
使用getFilename()
替代getLongFilename()
:
for (SftpClient.DirEntry entry : entries) {
LOGGER.info(entry.getFilename());
}
4. 使用SSHJ库
SSHJ是另一个轻量级SSH客户端库。添加依赖:
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
<version>0.38.0</version>
</dependency>
建立连接并认证(try-with-resources自动关闭):
try (SSHClient sshClient = new SSHClient()) {
sshClient.addHostKeyVerifier(new PromiscuousVerifier());
sshClient.connect(HOST);
sshClient.authPublickey(USER, PRIVATE_KEY);
// ...
}
创建SFTP客户端并列出文件:
try (SFTPClient sftpClient = sshClient.newSFTPClient()) {
List<RemoteResourceInfo> files = sftpClient.ls(REMOTE_DIR);
for (RemoteResourceInfo file : files) {
LOGGER.info("Filename: " + file.getName());
}
}
ls()
返回List<RemoteResourceInfo>
,通过getName()
获取文件名。
获取文件详细属性:
LOGGER.info("Permissions: " + file.getAttributes().getPermissions());
LOGGER.info("Last Modification Time: " + file.getAttributes().getMtime());
getAttributes()
提供权限、修改时间等元数据。
5. 总结
本文演示了使用三大Java SSH库(JSch、Apache Mina SSHD、SSHJ)与远程服务器交互的核心操作:
- ✅ 通过私钥建立安全连接
- ✅ 列出远程目录文件(详细/精简模式)
- ✅ 获取文件元数据
踩坑提示:
- 生产环境务必启用主机密钥验证
- 记得关闭连接释放资源
- 私钥文件权限需设置为600
完整示例代码见GitHub仓库。