首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

使用 JSch 實現 Java 遠程連接 Linux 服務器執行命令

     編輯:Java 相關知識

引言

在自動化運維、部署腳本或遠程管理場景中,Java 程式常需通過 SSH 連接 Linux 服務器執行命令。JSch (Java Secure Channel) 是一個純 Java 實現的 SSH2 庫,廣泛用於此類需求。本文提供一個完整、可直接運行的工具類示例,涵蓋會話建立、命令執行、結果讀取與資源釋放。

核心依賴

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version> <!-- 請使用最新穩定版 -->
</dependency>

完整工具類實現

import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Properties;

public class SshCommandExecutor {
    private static final Logger log = LoggerFactory.getLogger(SshCommandExecutor.class);
    private Session session;
    private final int timeout = 60_000; // 連接超時 60s

    /**
     * 建立 SSH 會話
     * @param host      服務器 IP/主機名
     * @param username  登錄用戶名
     * @param password  登錄密碼
     * @param port      SSH 端口,默認 22
     * @throws JSchException 連接失敗拋出
     */
    public void connect(String host, String username, String password, int port) throws JSchException {
        log.info("嘗試連接 {}:{} 用戶 {}", host, port, username);
        JSch jsch = new JSch();
        session = jsch.getSession(username, host, port);
        session.setPassword(password);

        // 禁用嚴格主機密鑰檢查,避免首次連接提示 known_hosts
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);

        session.setTimeout(timeout);
        session.connect(); // 實際建立 TCP 連接並完成 SSH 握手
        log.info("SSH 會話已建立");
    }

    /**
     * 在遠程服務器執行命令並返回標準輸出
     * @param command  要執行的 Shell 命令
     * @param charset  輸出流編碼,如 "UTF-8"
     * @return 命令輸出文本(每行以換行符分隔)
     * @throws Exception 執行或 IO 異常
     */
    public String executeCommand(String command, String charset) throws Exception {
        if (session == null || !session.isConnected()) {
            throw new IllegalStateException("SSH 會話未建立或已斷開");
        }
        ChannelExec channel = (ChannelExec) session.openChannel("exec");
        channel.setCommand(command);
        channel.setInputStream(null); // 無標準輸入
        channel.setErrStream(System.err); // 錯誤輸出重定向到當前進程 stderr

        try (InputStream in = channel.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(in, Charset.forName(charset)))) {

            channel.connect(); // 啟動命令執行
            StringBuilder output = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line).append('\n');
            }
            // 等待命令真正結束(可選,視業務而定)
            while (!channel.isClosed()) {
                Thread.sleep(100);
            }
            return output.toString();
        } finally {
            channel.disconnect(); // 釋放通道資源
        }
    }

    /** 關閉會話 */
    public void disconnect() {
        if (session != null && session.isConnected()) {
            session.disconnect();
            log.info("SSH 會話已關閉");
        }
    }

    // -------- 測試主方法 --------
    public static void main(String[] args) {
        SshCommandExecutor executor = new SshCommandExecutor();
        try {
            executor.connect("10.8.12.189", "jmuser", "root1234", 22);
            String result = executor.executeCommand("java -version", "UTF-8");
            System.out.println("命令輸出:\n" + result);
        } catch (Exception e) {
            log.error("執行失敗", e);
        } finally {
            executor.disconnect();
        }
    }
}

關鍵點解析

1. 會話複用

Session 對象建立開銷較大(TCP 握手、密鑰交換、認證),同一主機多次命令執行應復用同一 Session,僅重複打開 ChannelExec。

2. 編碼處理

遠程命令輸出編碼取決於服務器 Locale 設置(常見 UTF-8 或 GBK),傳入正確 charset 參數可避免中文亂碼。

3. 異常與資源管理

  • 使用 try-with-resources 確保流關閉。
  • finally 塊中 channel.disconnect() 防止通道洩漏導致服務器端殘留進程。
  • 生產環境建議增加重試邏輯、連接池(如 Apache Commons Pool 包裝 Session)。

4. 安全性提示

  • 生產環境避免硬編碼密碼,應使用密鑰對認證(jsch.addIdentity(privateKeyPath))或憑證管理系統。
  • StrictHostKeyChecking=no 僅適用於測試/內網環境,生產應維護 known_hosts 防止中間人攻擊。

進階用法

  • 交互式 Shell:使用 ChannelShell 替代 ChannelExec,支持多命令連續輸入。
  • SFTP 文件傳輸:ChannelSftp 實現上傳/下載/列表操作。
  • 端口轉發:session.setPortForwardingL(localPort, remoteHost, remotePort) 實現隧道代理。

總結

JSch 提供了輕量級、零原生依賴的 SSH 客戶端能力。通過封裝 Session 與 ChannelExec 生命周期,配合合理的異常處理與編碼設置,即可構建穩健的遠程命令執行組件,滿足自動化運維、CI/CD 流水線、遠程診斷等多種場景需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved