1. 程式人生 > >Java實踐 — SSH遠端執行Shell指令碼

Java實踐 — SSH遠端執行Shell指令碼

1. SSH簡介

        SSH是Secure Shell的縮寫,一種建立在應用層和傳輸層基礎上的安全協議。SSH在連線和傳送過程中會加密所有資料,可以用來在不同系統或者伺服器之間進行安全連線。SSH提供兩種的安全驗證方式:基於密碼的認證和基於密匙的認證。其中,基於密碼的認證比較簡單,只要知道遠端主機的使用者名稱和密碼,就可以進行登入。基於密匙的認證比較麻煩,而且連線比較耗時,這裡不詳細介紹。         有很多基於SSH協議的客戶端,例如:PuTTYOpenSSH、Xshell 4等,可以遠端連線幾乎所有UNIX平臺。同時,可以通過Linux命令列ssh [email protected]
連線到某主機。         在專案中,如何利用程式碼實現SSH,遠端執行Shell指令碼呢?JSch是Java Secure Channel的縮寫,是一個SSH2功能的純Java實現,具體資訊可以參考JSch官網。它允許你連線到一個SSH伺服器,並且可以使用埠轉發,X11轉發,檔案傳輸等,同時你也可以整合它的功能到你自己的應用程式。在使用前,需要下載並匯入JSch包:jsch-0.1.50.jar

2. 實現原理

        1. 根據遠端主機的IP地址,使用者名稱和埠,建立會話(Session);         2. 設定使用者資訊(包括密碼和Userinfo),然後連線session;         3. 在session上建立指定型別的通道(Channel),本文示例中採用ChannelExec型別的;         4. 設定channel上需要遠端執行的Shell指令碼,連線channel,就可以遠端執行該Shell指令碼;         5. 可以讀取遠端執行Shell指令碼的輸出,然後依次斷開channel和session的連線。

3. 示例程式碼及分析

  • SSHCommandExecutor.java:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Vector;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

/**
 * This class provide interface to execute command on remote Linux.
 */

public class SSHCommandExecutor {
    private String ipAddress;

    private String username;

    private String password;

    public static final int DEFAULT_SSH_PORT = 22;

    private Vector<String> stdout;

    public SSHCommandExecutor(final String ipAddress, final String username, final String password) {
        this.ipAddress = ipAddress;
        this.username = username;
        this.password = password;
        stdout = new Vector<String>();
    }

    public int execute(final String command) {
        int returnCode = 0;
        JSch jsch = new JSch();
        MyUserInfo userInfo = new MyUserInfo();

        try {
            // Create and connect session.
            Session session = jsch.getSession(username, ipAddress, DEFAULT_SSH_PORT);
            session.setPassword(password);
            session.setUserInfo(userInfo);
            session.connect();

            // Create and connect channel.
            Channel channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);

            channel.setInputStream(null);
            BufferedReader input = new BufferedReader(new InputStreamReader(channel
                    .getInputStream()));

            channel.connect();
            System.out.println("The remote command is: " + command);

            // Get the output of remote command.
            String line;
            while ((line = input.readLine()) != null) {
                stdout.add(line);
            }
            input.close();

            // Get the return code only after the channel is closed.
            if (channel.isClosed()) {
                returnCode = channel.getExitStatus();
            }

            // Disconnect the channel and session.
            channel.disconnect();
            session.disconnect();
        } catch (JSchException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return returnCode;
    }

    public Vector<String> getStandardOutput() {
        return stdout;
    }

    public static void main(final String [] args) {
        SSHCommandExecutor sshExecutor = new SSHCommandExecutor("xx.xx.xx.xx", "username", "password");
        sshExecutor.execute("uname -s -r -v");
        
        Vector<String> stdout = sshExecutor.getStandardOutput();
        for (String str : stdout) {
            System.out.println(str);
        }
    }
}
        getSession()只是建立一個session,需要設定必要的認證資訊之後,呼叫connect()才能建立連線。         呼叫openChannel(String type) 可以在session上開啟指定型別的channel。該channel只是被初始化,使用前需要先呼叫connect()進行連線。         Channel的型別可以為如下型別:
  • shell - ChannelShell 
  • exec - ChannelExec 
  • direct-tcpip - ChannelDirectTCPIP 
  • sftp - ChannelSftp 
  • subsystem - ChannelSubsystem
        其中,ChannelShell和ChannelExec比較類似,都可以作為執行Shell指令碼的Channel型別。它們有一個比較重要的區別:ChannelShell可以看作是執行一個互動式的Shell,而ChannelExec是執行一個Shell指令碼。
  • MyUserInfo:
import com.jcraft.jsch.UserInfo;

/**
 * This class provide interface to feedback information to the user.
 */
public class MyUserInfo implements UserInfo {
    private String password;

    private String passphrase;

    @Override
    public String getPassphrase() {
        System.out.println("MyUserInfo.getPassphrase()");
        return null;
    }

    @Override
    public String getPassword() {
        System.out.println("MyUserInfo.getPassword()");
        return null;
    }

    @Override
    public boolean promptPassphrase(final String arg0) {
        System.out.println("MyUserInfo.promptPassphrase()");
        System.out.println(arg0);
        return false;
    }

    @Override
    public boolean promptPassword(final String arg0) {
        System.out.println("MyUserInfo.promptPassword()");
        System.out.println(arg0);
        return false;
    }

    @Override
    public boolean promptYesNo(final String arg0) {
        System.out.println("MyUserInfo.promptYesNo()");
        System.out.println(arg0);
        if (arg0.contains("The authenticity of host")) {
            return true;
        }
        return false;
    }

    @Override
    public void showMessage(final String arg0) {
        System.out.println("MyUserInfo.showMessage()");
    }
}
        MyUserInfo實現了介面UserInfo,主要是為獲得執行執行的使用者資訊提供介面。大部分實現方法中,沒有做實質性的工作,只是輸出一下trace資訊,幫助判斷哪個方法被執行過。

4. 執行結果分析

        1. 如果不設定UserInfo,會丟擲JSchException異常,提示找不到host:
        2. 如果MyUserInfo實現了介面UserInfo,但是隻是@Override一些函式,會出現如下錯誤:
             雖然可以找到host,但是會拒絕訪問host。發現所有@Override函式中,get方法返回的都是null,prompt方法返回的都是false。         3. 為了判斷這些Override的methods中,那些是有用的,在每個method中加入trace資訊。發現只有promptYesNo(final String)會被呼叫到,輸出如下圖所示:
        4. promptYesNo(final String)是向用戶提出一個yes或者no的問題,來決定是否允許連線遠端主機。這才是決定連線是否成功的一個關鍵函式。如果返回值為true,則允許連線;如果返回值為false,則拒絕連線。最後正確連線後的輸出入下圖所示:

Reference

相關推薦

Java實踐SSH遠端執行Shell指令碼

1. SSH簡介         SSH是Secure Shell的縮寫,一種建立在應用層和傳輸層基礎上的安全協議。SSH在連線和傳送過程中會加密所有資料,可以用來在不同系統或者伺服器之間進行安全連線。SSH提供兩種的安全驗證方式:基於密碼的認證和基於密匙的認證。其中,基於

Java利用ssh工具遠端執行shell指令碼

1.首先下載ganymed-ssh2.jar   http://www.ganymed.ethz.ch/ssh2 2.SSHUtil工具類 import java.io.BufferedReader; import java.io.IOException; import j

Java之怎麼通過java去呼叫並執行shell指令碼以及問題總結(轉)

背景 我們在開發過程中,大部分是java開發, 而在文字處理過程中,主要就是指令碼進行開發。 java開發的特點就是我們可以很早地進行TDDL, METAQ 等等地對接; 而指令碼開發的特點就是在進行批處理的時候非常方便。 前陣子我遇到這麼一個需求場景: 對抓

Java 連線遠端Linux 伺服器執行 shell 指令碼檢視 CPU、記憶體、硬碟資訊

/* * Written by wei.Li and released to the public domain * Welcome to correct discussion as explained at * * ------------------------------------------

SSH遠端執行Linux Shell命令

使用強大的paramiko Linux伺服器需要注意防火牆設定和SSH的開啟 注意執行的shell命令前提是Linux系統上有的 #!/usr/bin/python #coding=utf-8 import paramiko import threading import

Java遠端呼叫shell指令碼(專案實戰)

前言        Java遠端呼叫shell指令碼,需要用到SSH建立連結(類似於xshell連線linux),然後再根據合法的引數進行shell指令碼呼叫 1 首先,從業務層開始,我這裡實現重傳指令碼的業務,程式碼如下.       //重傳     public

Java使用SSH遠端訪問Windows並執行命令

轉載至:http://blog.csdn.net/carolzhang8406/article/details/6760430 windows由於沒有預設的ssh server,因此在允許ssh之前需要先安裝ssh server。 下載freeSSHd http://ww

Linux下使用SSH非互動式遠端執行命令指令碼

原創文章,轉載請註明— 作者: 黃文海 出處: http://viscent.iteye.com/http://blog.viscenthuang.info     非互動式在遠端主機上執行命令或者指令碼可以幫助我們快速完成一些任務。比如,在叢集環境中,同時在各個結點上的日

使用Java定時執行shell指令碼

執行shell指令碼 Runtime.getRuntime().exec() 可以直接執行部分命令,不過執行一個shell指令碼的話更方便修改 public static void runshell(String path){

jenkins構建並遠端釋出後執行shell指令碼

由於jenkins遠端釋出war檔案到不同環境下的tomcat下時,會先刪除同名檔案後再進行遠端拷貝,此時保留在本地的配置檔案需收到copy。 為實現自動化釋出,特在釋出後執行shell指令碼,遠端c

publish over ssh 實現 Jenkins 遠端部署 / jenkins 遠端執行shell 一鍵遠端釋出 tomcat / jenkins分別釋出多個專案到多個遠端主機

1. 以下是本地Jenkins生成war包直接釋出本機。參照了(jenkins 遠端執行shell 一鍵遠端釋出 tomcat) BUILD_ID=DONTKILLME  (加這個原因是因為沒加之前用command startup tomcat一直啟動失敗而shutd

Jenkins Pipeline執行shell指令碼遠端連線主機時 Host key verification failed

                      --昨夜西風凋碧樹,獨上高樓,望盡天涯路 錯誤描述 當Jenkins Pipeline通過執行shell指令碼,遠端連線伺服器釋出專案的時候出現校驗失敗: Jenkins已經配置了免密登陸遠端伺服器,以及在Jenki

Java執行Shell指令碼超時控制

Java的Runtime可以執行命令列指令碼,某些特定場合需要對指令碼的執行時間進行控制,防止指令碼某些異常情況下,一直未能正確結束,導致Java主程序掛起。本文的程式對這一過程進行了控制 Java程式碼 import org.slf4j.Logger;   import org.slf4j.Log

java呼叫linux中的shell指令碼並返回執行結果

來自:http://blog.sina.com.cn/s/blog_8e5354210101ku2e.html process這個類是一個抽象類,封裝了一個程序(你在呼叫linux的命令或者shell指令碼就是為了執行一個在linux下執行的程式,所以應該使用process

ssh 遠端執行遠端機上的指令碼或命令

單命令執行: ssh [email protected] "cd /home ; ls" 今天 遠端執行命令發現了一個問題: 當執行下面命令 ssh -o ConnectTimeout=60 -qn [email protected] "cd

Java 執行shell 指令碼

直接執行在環境變數path的命令 可能會報錯 Java 會找/bin下面的命令執行 命令路徑要寫絕對的....!!!!  比如/bin/sh 代替 sh 執行命令方法 public static String exec(String cmd) { System.out.pr

java遠端執行shell命令

1、連線伺服器,執行shell的方法package com.shishike.susie.utility; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.P

使用crontab定時執行shell指令碼

原帖地址:http://blog.chinaunix.net/uid-429659-id-4510419.html 使用crontab你可以在指定的時間執行一個shell指令碼或者一系列Linux命令。例如系統管理員安排一個備份任務使其每天都執行 入門 # cronta

怎麼在後臺執行shell指令碼

後臺執行指令碼 執行指令碼test.sh:./test.sh 中斷指令碼test.sh:ctrl+c 在1的基礎上將執行中的test.sh,切換到後臺並暫停:ctrl+z 執行ctrl+z後,test.sh在後臺是暫停狀態(stopped),使用命令:bg number讓

JAVA使用Runtime.getRuntime()執行python指令碼檔案

java呼叫python(含anaconda) 注意: 1、python指令碼必須都用的是絕對路徑(可以拼接) 2、python指令碼呼叫自定義的模組時要將模組路徑新增到環境中。如果用sys.append(模組絕對路徑),要每一個指令碼都要新增專案所在的路徑。 cmd命令列執行:&n