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(默认)、yesno
✅ 开发测试设为 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 包装。

两个库各有优势,按需选择即可。


原始标题:SSH Connection With Java | Baeldung

» 下一篇: Java周报,350