利用ganymed-ssh2远程执行其它Linux机器上的shell命令

时间:2022-04-23
本文章向大家介绍利用ganymed-ssh2远程执行其它Linux机器上的shell命令,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

实际应用中,有时候需要从web管理界面上,远程去启动其它linux主机上的程序,利用ssh协议可以方便的满足这一需求。事实上hadoop架构中,从nn上启动dn时,就是利用了免密码ssh登录。ganymed-ssh2是一个实现了ssh协议的开源项目,项目地址为:http://ganymed-ssh-2.googlecode.com/ (下载源码要翻强,众所周知的原因),如果只是使用的话,pom.xml添加以下依赖项就行了:

1         <dependency>
2             <groupId>ch.ethz.ganymed</groupId>
3             <artifactId>ganymed-ssh2</artifactId>
4             <version>262</version>
5         </dependency>

为了方便起见,封装了一个工具类SSHUtil.java(已托管在taobao.org上)

package com.cnblogs.yjmyzz.utils;

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * SSH工具类(可远程执行其它Linux机器上的Shell命令)
 * Created by jimmy on 2015/7/6.
 * http://code.taobao.org/p/y-lib/src/trunk/src/main/java/com/cnblogs/yjmyzz/utils/SSHUtil.java
 */
public class SSHUtil {

    /**
     * 连接到主机
     *
     * @param hostname
     * @param username
     * @param password
     * @return
     * @throws Exception
     */
    private static Connection getConnection(String hostname, String username, String password) throws Exception {
        Connection conn = null;
        try {
            conn = new Connection(hostname);
            conn.connect();
            boolean isAuthenticated = conn.authenticateWithPassword(username, password);
            if (isAuthenticated == false) {
                throw new IOException("Authentication failed.");
            }
        } catch (Exception e) {
            throw new IOException("username or password error.");
        }
        return conn;
    }


    /**
     * 执行远程命令
     *
     * @param hostname 远程主机IP
     * @param username 用户名
     * @param password 密码
     * @param command  需要执行的命令
     * @param timeout  超时时间(秒)
     * @return
     * @throws Exception
     */
    public static String execRemoteCommand(String hostname, String username, String password, String command, long timeout)
            throws Exception {
        Connection conn = getConnection(hostname, username, password);
        StringBuilder sb = new StringBuilder();
        Session session = null;
        try {
            session = conn.openSession();
            session.requestPTY("vt100", 80, 24, 640, 480, null);
            session.execCommand(command);
            InputStream stdout = new StreamGobbler(session.getStdout());
            BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
            long start = System.currentTimeMillis();
            char[] arr = new char[512];
            int read;
            int i = 0;
            while (true) {
                read = br.read(arr, 0, arr.length);
                if (read < 0 || (System.currentTimeMillis() - start) > timeout * 1000) {
                    break;
                }
                sb.append(new String(arr, 0, read));
                i++;
            }
        } finally {
            if (session != null) {
                session.close();
            }
            if (conn != null) {
                conn.close();
            }
        }
        return sb.toString();
    }


    /**
     * 执行远程命令(默认5秒超时)
     *
     * @param hostname 远程主机IP
     * @param username 用户名
     * @param password 密码
     * @param command  需要执行的命令
     * @return
     * @throws Exception
     */
    public static String execRemoteCommand(String hostname, String username, String password, String command)
            throws Exception {
        return execRemoteCommand(hostname, username, password, command, 5);
    }


    /**
     * 批量执行远程命令
     *
     * @param hostname 远程主机IP
     * @param username 用户名
     * @param password 密码
     * @param command  需要执行的命令列表
     * @param timeout  超时时间(秒)
     * @return
     * @throws Exception
     */
    public static String execRemoteCommand(String hostname, String username, String password, String[] command, long timeout)
            throws Exception {
        Connection conn = getConnection(hostname, username, password);
        StringBuilder sb = new StringBuilder();
        Session session = null;
        try {
            for (int t = 0; t < command.length; t++) {
                session = conn.openSession();
                session.requestPTY("vt100", 80, 24, 640, 480, null);
                session.execCommand(command[t]);
                InputStream stdout = new StreamGobbler(session.getStdout());
                BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
                long start = System.currentTimeMillis();
                char[] arr = new char[512];
                int read;
                int i = 0;
                while (true) {
                    read = br.read(arr, 0, arr.length);
                    if (read < 0 || (System.currentTimeMillis() - start) > timeout * 1000) {
                        break;
                    }
                    sb.append(new String(arr, 0, read));
                    i++;
                }
                session.close();
            }
        } finally {
            if (conn != null) {
                conn.close();
            }
        }
        return sb.toString();
    }

    /**
     * 批量执行远程命令(默认5秒超时)
     *
     * @param hostname 远程主机IP
     * @param username 用户名
     * @param password 密码
     * @param command  需要执行的命令列表
     * @return
     * @throws Exception
     */
    public static String execRemoteCommand(String hostname, String username, String password, String[] command)
            throws Exception {
        return execRemoteCommand(hostname, username, password, command, 5);
    }
}

使用要点:

1. 如果要连续执行多个命令,用&&连接,比如:先 cd / 切换到根目录,然后再ls 根目录下的所有文件,可以这样调用:

    public static void main(String[] args) {
        String hostname = "172.21.129.**";
        String username = "root";
        String password = "***";
        try {
            System.out.println(SSHUtil.execRemoteCommand(hostname, username, password,
                    "pwd&&cd /&&pwd&&ls"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

上面的命令相当于在同一个session下,连续执行

pwd

cd /

pwd

ls

2. 如果要以后台进程调用命令,传入命令时,直接加 nohup 即可