1. 简介
SSH(Secure Shell)是一种网络协议,允许一台计算机在不安全的网络中安全地连接到另一台计算机。本文将演示如何 使用 JSch 和 Apache MINA SSHD 两个 Java 库建立与远程 SSH 服务器的连接。
示例中,我们会完成以下流程:
- 建立 SSH 连接
- 执行一条命令
- 读取输出并打印到控制台
- 关闭连接
代码尽量保持简洁,聚焦核心逻辑,避免冗余。
2. JSch
JSch 是 SSH2 协议的纯 Java 实现,支持连接 SSH 服务器、端口转发、X11 转发和文件传输。它采用 BSD 风格许可证,是 Java 中实现 SSH 功能的主流选择之一。
首先,在 pom.xml
中引入依赖:
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.55</version>
</dependency>
2.1 实现方式
使用 JSch 建立 SSH 连接,需要以下信息:
- ✅ 用户名
- ✅ 密码
- ✅ 主机地址(host)
- ✅ SSH 端口(默认为 22,但可自定义)
以下是核心实现代码:
public static void listFolderStructure(String username, String password,
String host, int port, String command) throws Exception {
Session session = null;
ChannelExec channel = null;
try {
session = new JSch().getSession(username, host, port);
session.setPassword(password);
session.setConfig("StrictHostKeyChecking", "no");
session.connect();
channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(command);
ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
channel.setOutputStream(responseStream);
channel.connect();
while (channel.isConnected()) {
Thread.sleep(100);
}
String responseString = new String(responseStream.toByteArray());
System.out.println(responseString);
} finally {
if (session != null) {
session.disconnect();
}
if (channel != null) {
channel.disconnect();
}
}
}
关键点解析
Session
:代表与 SSH 服务器的一次会话,需设置用户名、密码和连接参数。ChannelExec
:用于执行远程命令的通道类型。setOutputStream()
:指定命令输出写入的流,便于后续读取结果。Thread.sleep(100)
:简单轮询等待命令执行完成(生产环境建议加超时控制)。
⚠️ 务必在 finally 块中关闭 session 和 channel,否则可能引发资源泄漏。
常用配置项说明
配置项 | 说明 |
---|---|
StrictHostKeyChecking |
是否校验主机公钥。可选值:ask (默认)、yes 、no 。✅ 开发测试设为 no 可自动添加新主机;❌ 生产环境建议设为 yes 防止中间人攻击 |
compression.s2c |
服务端到客户端是否启用压缩。值:zlib / none (默认) |
compression.c2s |
客户端到服务端是否启用压缩。值同上 |
踩坑提醒:
StrictHostKeyChecking=no
虽然方便,但在生产环境存在安全风险,建议结合known_hosts
文件管理可信主机。
3. Apache MINA SSHD
Apache MINA SSHD 是基于 Apache MINA 的高性能异步 SSH 实现,适用于需要高并发或自定义 SSH 服务的场景。它不仅支持客户端连接,还能用于构建 SSH 服务端。
添加 Maven 依赖:
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>2.5.1</version>
</dependency>
3.1 实现方式
以下是使用 MINA SSHD 连接远程服务器并执行命令的示例:
public static void listFolderStructure(String username, String password,
String host, int port, long defaultTimeoutSeconds, String command) throws IOException {
SshClient client = SshClient.setUpDefaultClient();
client.start();
try (ClientSession session = client.connect(username, host, port)
.verify(defaultTimeoutSeconds, TimeUnit.SECONDS).getSession()) {
session.addPasswordIdentity(password);
session.auth().verify(defaultTimeoutSeconds, TimeUnit.SECONDS);
try (ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
ClientChannel channel = session.createChannel(Channel.CHANNEL_SHELL)) {
channel.setOut(responseStream);
try {
channel.open().verify(defaultTimeoutSeconds, TimeUnit.SECONDS);
try (OutputStream pipedIn = channel.getInvertedIn()) {
pipedIn.write(command.getBytes());
pipedIn.flush();
}
channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED),
TimeUnit.SECONDS.toMillis(defaultTimeoutSeconds));
String responseString = new String(responseStream.toByteArray());
System.out.println(responseString);
} finally {
channel.close(false);
}
}
} finally {
client.stop();
}
}
关键点对比
SshClient.setUpDefaultClient()
:创建一个带有默认配置(加密算法、压缩、密钥交换等)的客户端实例,开箱即用。- 所有操作都支持显式超时控制(
.verify(timeout, unit)
),避免无限等待 ❌ - 使用
try-with-resources
管理资源,更安全 CHANNEL_SHELL
模拟完整 shell 会话,适合执行多条命令或交互式操作
✅ 注意:SSHD 会将整个 shell 会话的输出(包括提示符、回显等)写入 responseStream
,而 JSch 仅返回命令执行结果。这意味着你可能需要对输出做清洗处理。
例如执行 ls
后,实际输出可能是:
$ ls
file1.txt
file2.log
$
你需要根据 $
或换行符提取有效内容。
官方文档详见:Apache MINA SSHD GitHub Docs
4. 总结
本文通过两个主流 Java 库展示了如何建立 SSH 连接并执行远程命令:
特性 | JSch | Apache MINA SSHD |
---|---|---|
✅ 易用性 | 高,API 简单直观 | 中,需理解事件模型 |
✅ 社区成熟度 | 非常成熟,广泛使用 | 成熟,功能更强 |
✅ 超时控制 | 需手动轮询 | 内建超时机制,更安全 |
✅ 多命令支持 | 较弱 | 强(支持完整 shell) |
✅ 服务端支持 | ❌ 不支持 | ✅ 支持构建 SSH 服务 |
使用建议
- 🔹 日常运维脚本、简单命令执行 → 选 JSch,简单粗暴够用
- 🔹 高并发、需自定义协议、或要搭建 SSH 服务 → 选 Apache MINA SSHD
踩坑总结:别忘了关闭资源!无论是 JSch 的
Session
还是 SSHD 的Client
,不关闭会导致连接堆积、内存溢出。推荐用 try-finally 或 try-with-resources 包装。
两个库各有优势,按需选择即可。