利用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 即可 

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python小屋

使用Python检查密码安全程度

本文主要演示几种内置用法的用法和代码优化技巧,所以没有使用正则表达式。 import string def check(pwd): #密码必须至少包含6个字符...

3435
来自专栏Astropeak

Spring使用 --- 基本概念(一):DI,依赖注入

1232
来自专栏hbbliyong

你真的了解如何将 Nginx 配置为Web服务器吗

阅读之前,建议先阅读初识 Nginx。 之后,我们来了解一下 Nginx 配置。 抽象来说,将 Nginx 配置为 Web 服务器就是定义处理哪些 URLS 和...

6127
来自专栏Android群英传

Google最新源码编译系统

2752
来自专栏Vamei实验室

来玩Play框架03 模板

在上一章节中,我把字符串通过ok()返回给客户。我可以把一个完整的html页面放入字符串中返回。然而,现代的框架都提供了更好的方法——模板。模板将视图和数据分开...

2065
来自专栏决胜机器学习

Redis专题(十)——Redis存储Session

Redis专题(十) ——Redis存储session (原创内容,转载请注明来源,谢谢) 一、概述 PHP默认是将session存于服务器...

3775
来自专栏JAVA技术zhai

干货:Java多线程详解(内附源码)

3534
来自专栏小二的折腾日记

多线程

进程:是一个正在执行中的程序。 每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。 线程:就是进程中的一个独立的控制单元。 线程在控制...

521
来自专栏Python攻城狮

Pyramid中的request和response1.Request2.Multidict3.Response

官方API:pyramid.request、pyramid.response 和 pyramid.httpexceptions。

881
来自专栏北京马哥教育

Linux Shell脚本面试25问

Q:1 Shell脚本是什么、它是必需的吗? 答:一个Shell脚本是一个文本文件,包含一个或多个命令。作为系统管理员,我们经常需要使用多个命令来完成一项任务...

3745

扫码关注云+社区

领取腾讯云代金券