Ganymed SSH-2

    咱們在平常開發中,有時候會遇到觸發一個linux命令,好比清理臨時文件,或者觸發一個shell命令。那麼這個時候就須要經過java去調用shell命令。 這裏咱們使用java自帶的ProcessBuilder 來完成任務。ProcessBuilder類是用於建立操做系統進程。經過本機遠程ssh到另一臺機器上去執行shell命令的需求,這種使用方式常常用於一臺機器集羣管理其餘機器的需求。html

    java裏能夠經過Ganymed SSH-2, Expect4j等實現ssh登陸,基步驟以下:java

1、下載安裝linux

http://www.ganymed.ethz.ch/ssh2/下載,咱們用的是ganymed-ssh2-build210.zipshell

在eclipse裏新建一個測試工程,並將解壓後的ganymed-ssh2-build210.jar拷到工程的lib目錄下,而後在工程屬性的java build path裏添加這個jar的library。apache


2、sshwindows

將解壓後的examples目錄下的Basic.java 拷到工程的src目錄,編譯運行之後能夠在控制檯看到輸出結果。除了執行一條命令,也能夠執行一個shell腳本。session

測試腳本test.sh:
app

#! /bin/sh
echo "testing shell"
ls

運行cmd的Java程序:eclipse

public boolean realRun(String cmd) {
		cmd = test.sh
//		LocalShellExecutor exe = new LocalShellExecutor();
		RmtShellExecutor exe = new RmtShellExecutor("192.168.1.118", "22", "root", "123456");
//		RmtShellExecutor exe = new RmtShellExecutor("127.0.0.1", "22", "root", "123456");
		logger.info("cmd:" + cmd);
		int ret = exe.exec(cmd);
		outErr = exe.getErrorMessage();
		outStr = exe.getResult();
		result = (ret == 0 ? true : false);
		if (!result) {
			logger.error("err:" + outErr);
		}
		logger.info("outStr:" + outStr);
		return result;
	}

本地調用:ssh

package scnas.controller;

import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import scnas.iface.ShellExecutor;
import scnas.model.Const;

public class LocalShellExecutor implements ShellExecutor {
    /**標準輸出**/
    private String outStr;
    /**錯誤輸出**/
    private String outErr;
    
        
	@Override
	public int exec(String cmds) {
		int ret = -1;
		try{
			final Process process = Runtime.getRuntime().exec(cmds);
//			Thread inputThread = new Thread(new Runnable(){
//				@Override
//				public void run() 
//				{
					try {
						InputStream inputStream = process.getInputStream();
						InputStreamReader reader = new InputStreamReader(inputStream);
						int readed = 0;
						char[] chs = new char[1024];
						StringBuffer buffer = new StringBuffer();
						while( (readed=reader.read(chs)) != -1 ){		
							buffer.append(chs,0,readed);
						}
						
						outStr = buffer.toString();
						
						logger.info(outStr);

					}catch(Exception ex){
						logger.error(ex.getMessage(), ex);
					}
//				}
//			});
			
//			Thread errorThread = new Thread(new Runnable(){
//				@Override
//				public void run() 
//				{
					try {
						InputStream inputStream = process.getErrorStream();
						InputStreamReader reader = new InputStreamReader(inputStream);
						int readed = 0;
						char[] chs = new char[1024];
						StringBuffer errorBuffer = new StringBuffer();
						while( (readed=reader.read(chs)) != -1 )
						{
							errorBuffer.append(chs,0,readed);
						}
						outErr = errorBuffer.toString();
					}catch(Exception ex){
						logger.error(ex.getMessage(), ex);
					}
//				}
//			});
			
//			errorThread.start();
//			inputThread.start();
			
			process.getOutputStream().close(); 
						
			ret = process.waitFor(); 
			
		} catch(Exception e){ 
			outErr = e.getMessage();
		} 
		
		if( ret != 0 )
			logger.error("LocalShellExecutor ERROR: " + outErr);
		logger.info("LocalShellExecutor: " + outStr);
		return ret;
	}

	@Override
	public String getErrorMessage() {
		return outErr;
	}

	@Override
	public String getResult() {
		return outStr;
	}
	
	public static void main(String args[]){
		LocalShellExecutor localShellExecutor = new LocalShellExecutor();
		localShellExecutor.exec(Const.PATH + Const.HOST);
	}

	public String getOutStr() {
		return outStr;
	}

	public void setOutStr(String outStr) {
		this.outStr = outStr;
	}

	public String getOutErr() {
		return outErr;
	}

	public void setOutErr(String outErr) {
		this.outErr = outErr;
	}


	private static final Log logger = LogFactory.getLog(LocalShellExecutor.class);
}

遠程調用:

package scnas.controller;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import scnas.iface.ShellExecutor;
import scnas.model.Const;
import ch.ethz.ssh2.ChannelCondition;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.SCPClient;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;

/**
 * 遠程執行shell腳本類
 */
public class RmtShellExecutor implements ShellExecutor{
    
    /**  */
    private Connection conn;
    /** 遠程機器IP */
    private String     ip;
    /** 用戶名 */
    private String	port;
    private String     usr;
    /** 密碼 */
    private String     psword;
    private String     charset = Charset.defaultCharset().toString();

    private static final int TIME_OUT = 1000 * 5 * 60;
    
    /**標準輸出**/
    private String outStr;
    /**錯誤輸出**/
    private String outErr;
    
    private static final Log logger = LogFactory.getLog(RmtShellExecutor.class);

    /**
     * 構造函數
     * @param ip
     * @param usr
     * @param ps
     */
    public RmtShellExecutor(String ip, String port, String usr, String ps) {
        this.ip = ip;
        this.port = port;
        this.usr = usr;
        this.psword = ps;
    }

    /**
     * 登陸
     * 
     * @return
     * @throws IOException
     */
    private boolean login() throws IOException {
        conn = new Connection(ip, Integer.parseInt(port));
        conn.connect();
        return conn.authenticateWithPassword(usr, psword);
    }

    /**
     * 執行腳本
     * 
     * @param cmds
     * @return
     * @throws Exception
     */
    @Override
    public int exec(String cmds){
        InputStream stdOut = null;
        InputStream stdErr = null;

        int ret = -1;
        try {
            if (login()) {
                // Open a new {@link Session} on this connection
                Session session = conn.openSession();
                // Execute a command on the remote machine.
                session.execCommand(cmds);
                stdOut = new StreamGobbler(session.getStdout());
                outStr = processStream(stdOut, charset);
                
                stdErr = new StreamGobbler(session.getStderr());
                outErr = processStream(stdErr, charset);
                
                session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
                ret = session.getExitStatus();
            } else{
            	outErr = "登陸遠程機器失敗:" + ip;
            }
        }catch(Exception e){
        	outErr = "遠程操做失敗:" + ip;
        }finally{
            if (conn != null) {
                conn.close();
            }
            IOUtils.closeQuietly(stdOut);
            IOUtils.closeQuietly(stdErr);
        }
        
		if( ret != 0 ){
			logger.error("RmtShellExecutor ERROR: " + outErr);
//			Loginfo loginfo = new Loginfo("ERROR", "", "RmtShellExecutor", cmds + " - " + outStr);
//			scnasService.loginfoAdd(loginfo);
		}else{
			logger.info(cmds +  ": " + outStr);
//			Loginfo loginfo = new Loginfo("INFO", "", "RmtShellExecutor", cmds + " - " + outErr);
//			scnasService.loginfoAdd(loginfo);
		}
		
        return ret;
    }
    
    public int exec(String cmds, boolean wait){
        int ret = -1;
        try {
            if (login()) {
                // Open a new {@link Session} on this connection
                Session session = conn.openSession();
                // Execute a command on the remote machine.
                session.execCommand(cmds);
                
            	session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT );
            	ret = session.getExitStatus();
            } else{
            	outErr = "登陸遠程機器失敗:" + ip;
            }
        }catch(Exception e){
        	outErr = "遠程操做失敗:" + ip;
        }finally{
            if (conn != null) {
                conn.close();
            }
        }
        
		if( ret != 0 )
			logger.error("RmtShellExecutor wait ERROR!");
		
        return ret;
    }    
    
    public void scp(String localfile, String remoteDirectory){
        try {
			if (login()) {
			    SCPClient sCPClient = new SCPClient(conn);
			    sCPClient.put(localfile, remoteDirectory, "0755");
			} else{
				outErr = "登陸遠程機器失敗:" + ip;
			}
		} catch (IOException e) {
			outErr = "遠程操做失敗:" + ip;
		}finally{
            if (conn != null) {
                conn.close();
            }
        }
    }

    /**
     * @param in
     * @param charset
     * @return
     * @throws IOException
     * @throws UnsupportedEncodingException
     */
    private String processStream(InputStream in, String charset) throws Exception {
        byte[] buf = new byte[1024];
        StringBuilder sb = new StringBuilder();
        while (in.read(buf) != -1) {
            sb.append(new String(buf, charset));
            buf = new byte[1024];
        }
        return sb.toString();
    }

	@Override
	public String getErrorMessage() {
		return outErr;
	}

	@Override
	public String getResult() {
		return outStr;
	}

	public Connection getConn() {
		return conn;
	}

	public void setConn(Connection conn) {
		this.conn = conn;
	}

	public String getIp() {
		return ip;
	}

	public void setIp(String ip) {
		this.ip = ip;
	}

	public String getPort() {
		return port;
	}

	public void setPort(String port) {
		this.port = port;
	}

	public String getUsr() {
		return usr;
	}

	public void setUsr(String usr) {
		this.usr = usr;
	}

	public String getPsword() {
		return psword;
	}

	public void setPsword(String psword) {
		this.psword = psword;
	}

	public String getCharset() {
		return charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public String getOutStr() {
		return outStr;
	}

	public void setOutStr(String outStr) {
		this.outStr = outStr;
	}

	public String getOutErr() {
		return outErr;
	}

	public void setOutErr(String outErr) {
		this.outErr = outErr;
	}

	public static int getTimeOut() {
		return TIME_OUT;
	}

	public static Log getLogger() {
		return logger;
	}

	public static void main(String args[]){
        RmtShellExecutor exe = new RmtShellExecutor("10.10.1.101", "22", "root", "123456");
        System.out.println(Const.SHELL + Const.PATH + Const.HOST);
//        System.out.println("exit state:" + exe.exec("gluster volume status vol4 detail"));
//        System.out.println("result:" + exe.getResult());
//        System.out.println("err:" + exe.getErrorMessage());
//        exe.scp("/tmp/1", "/tmp");
        exe.exec("scnas peer status");
//        System.out.println("result:" + exe.getResult());
    }
    
}

在eclipse裏運行之後的結果爲:

Here is some information about the remote host:
testing shell
1
test.sh
ExitCode: 0

須要注意的是在一個session裏只能執行一次命令,所以若是想在server上執行多個命令,要麼打開多個session,要麼在一個session裏去執行一個shell腳本,shell腳本里去執行多個命令。

每次執行完之後,若是正確將返回ExitCode: 0,所以程序裏能夠經過sess.getExitStatus()來判斷命令是否被正確執行。


3、 scp

首先在程序裏import ch.ethz.ssh2.SCPClient;   

而後經過下面的方法來實現:

SCPClient scpClient = conn.createSCPClient();   
scpClient.put("localFiles", "remoteDirectory"); //從本地複製文件到遠程目錄   
scpClient.get("remoteFiles","localDirectory"); //從遠程獲取文件

如上

public void scp(String localfile, String remoteDirectory){}

例如:

scpClient.put("D:\\localTest.txt", "/home/bill/"); 須要注意的是windows的本地目錄要用雙斜槓來分隔目錄。
scpClient.put("/home/bill/remoteTest.txt", "D:\\");


4、sftp

首先在程序裏import ch.ethz.ssh2.SFTPv3Client;

SFTPv3Client sftpClient = new SFTPv3Client(conn);   
sftpClient.mkdir("newRemoteDir", 0755); //遠程新建目錄 ,第二個參數是建立的文件夾的讀寫權限  
sftpClient.rmdir("oldRemoteDir"); //遠程刪除目錄

另外還有建立刪除文件,讀寫文件等接口,參見http://www.ganymed.ethz.ch/ssh2/javadoc/ch/ethz/ssh2/SFTPv3Client.html

相關文章
相關標籤/搜索