1. SSH简介

        SSH是Secure Shell的缩写,一种建立在应用层和传输层基础上的安全协议。SSH在连接和传送过程中会加密所有数据,可以用来在不同系统或者服务器之间进行安全连接。SSH提供两种的安全验证方式:基于密码的认证和基于密匙的认证。其中,基于密码的认证比较简单,只要知道远程主机的用户名和密码,就可以进行登录。基于密匙的认证比较麻烦,而且连接比较耗时,这里不详细介绍。
        有很多基于SSH协议的客户端,例如:PuTTYOpenSSH、Xshell 4等,可以远程连接几乎所有UNIX平台。同时,可以通过Linux命令行ssh uername@host连接到某主机。
        在项目中,如何利用代码实现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:

    1. import java.io.BufferedReader;
    2. import java.io.InputStreamReader;
    3. import java.util.Vector;
    4.  
    5. import com.jcraft.jsch.Channel;
    6. import com.jcraft.jsch.ChannelExec;
    7. import com.jcraft.jsch.JSch;
    8. import com.jcraft.jsch.JSchException;
    9. import com.jcraft.jsch.Session;
    10.  
    11. /**
    12. * This class provide interface to execute command on remote Linux.
    13. */
    14.  
    15. public class SSHCommandExecutor {
    16. private String ipAddress;
    17.  
    18. private String username;
    19.  
    20. private String password;
    21.  
    22. public static final int DEFAULT_SSH_PORT = 22;
    23.  
    24. private Vector<String> stdout;
    25.  
    26. public SSHCommandExecutor(final String ipAddress, final String username, final String password) {
    27. this.ipAddress = ipAddress;
    28. this.username = username;
    29. this.password = password;
    30. stdout = new Vector<String>();
    31. }
    32.  
    33. public int execute(final String command) {
    34. int returnCode = 0;
    35. JSch jsch = new JSch();
    36. MyUserInfo userInfo = new MyUserInfo();
    37.  
    38. try {
    39. // Create and connect session.
    40. Session session = jsch.getSession(username, ipAddress, DEFAULT_SSH_PORT);
    41. session.setPassword(password);
    42. session.setUserInfo(userInfo);
    43. session.connect();
    44.  
    45. // Create and connect channel.
    46. Channel channel = session.openChannel("exec");
    47. ((ChannelExec) channel).setCommand(command);
    48.  
    49. channel.setInputStream(null);
    50. BufferedReader input = new BufferedReader(new InputStreamReader(channel
    51. .getInputStream()));
    52.  
    53. channel.connect();
    54. System.out.println("The remote command is: " + command);
    55.  
    56. // Get the output of remote command.
    57. String line;
    58. while ((line = input.readLine()) != null) {
    59. stdout.add(line);
    60. }
    61. input.close();
    62.  
    63. // Get the return code only after the channel is closed.
    64. if (channel.isClosed()) {
    65. returnCode = channel.getExitStatus();
    66. }
    67.  
    68. // Disconnect the channel and session.
    69. channel.disconnect();
    70. session.disconnect();
    71. } catch (JSchException e) {
    72. // TODO Auto-generated catch block
    73. e.printStackTrace();
    74. } catch (Exception e) {
    75. e.printStackTrace();
    76. }
    77. return returnCode;
    78. }
    79.  
    80. public Vector<String> getStandardOutput() {
    81. return stdout;
    82. }
    83.  
    84. public static void main(final String [] args) {
    85. SSHCommandExecutor sshExecutor = new SSHCommandExecutor("xx.xx.xx.xx", "username", "password");
    86. sshExecutor.execute("uname -s -r -v");
    87.  
    88. Vector<String> stdout = sshExecutor.getStandardOutput();
    89. for (String str : stdout) {
    90. System.out.println(str);
    91. }
    92. }
    93. }

    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:
    1. import com.jcraft.jsch.UserInfo;
    2.  
    3. /**
    4. * This class provide interface to feedback information to the user.
    5. */
    6. public class MyUserInfo implements UserInfo {
    7. private String password;
    8.  
    9. private String passphrase;
    10.  
    11. @Override
    12. public String getPassphrase() {
    13. System.out.println("MyUserInfo.getPassphrase()");
    14. return null;
    15. }
    16.  
    17. @Override
    18. public String getPassword() {
    19. System.out.println("MyUserInfo.getPassword()");
    20. return null;
    21. }
    22.  
    23. @Override
    24. public boolean promptPassphrase(final String arg0) {
    25. System.out.println("MyUserInfo.promptPassphrase()");
    26. System.out.println(arg0);
    27. return false;
    28. }
    29.  
    30. @Override
    31. public boolean promptPassword(final String arg0) {
    32. System.out.println("MyUserInfo.promptPassword()");
    33. System.out.println(arg0);
    34. return false;
    35. }
    36.  
    37. @Override
    38. public boolean promptYesNo(final String arg0) {
    39. System.out.println("MyUserInfo.promptYesNo()");
    40. System.out.println(arg0);
    41. if (arg0.contains("The authenticity of host")) {
    42. return true;
    43. }
    44. return false;
    45. }
    46.  
    47. @Override
    48. public void showMessage(final String arg0) {
    49. System.out.println("MyUserInfo.showMessage()");
    50. }
    51. }
            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

           JSch官网 
           JSch API

来自:http://blog.csdn.net/jmyue/article/details/14003783

Java实践 — SSH远程执行Shell脚本的更多相关文章

  1. Java实践 — SSH远程执行Shell脚本(转)

    原文地址:http://www.open-open.com/lib/view/open1384351384024.html 1. SSH简介         SSH是Secure Shell的缩写,一 ...

  2. Java SSH远程执行Shell脚本实现(转)

    前言 此程序需要ganymed-ssh2-build210.jar包(下载地址:http://www.ganymed.ethz.ch/ssh2/) 为了调试方便,可以将\ganymed-ssh2-bu ...

  3. JAVA远程执行Shell脚本类

    1.java远程执行shell脚本类 package com.test.common.utility; import java.io.IOException; import java.io.Input ...

  4. [linux] ssh远程执行本地脚本

    1.ssh密钥登录 略 2.免确认机器指纹,ssh -o StrictHostKeyChecking=no [root@XM-v125 ~]# ssh wykai@192.168.0.110 The ...

  5. Python ssh 远程执行shell命令

    工具 python paramiko 远程执行命令 import paramiko ssh = paramiko.SSHClient() key = paramiko.AutoAddPolicy() ...

  6. Java SSH远程执行Shell命令、shell脚本实现(Ganymed SSH)

    jar包下载地址: http://www.ganymed.ethz.ch/ssh2/ 此源码的好处就是没有依赖很多其他的包,拷贝过来干干净净.具体代码实现可以看下文,或参考官方文档,在下载的压缩包里g ...

  7. 远程执行shell脚本的小技巧

    很多时候需要批量跑脚本执行任务,但又不想分发再执行,而是直接一条命令下去就跑脚本,该怎么玩比较嗨? 例如以下脚本: #!/bin/bash echo "$@" echo " ...

  8. 远程执行shell脚本

    ssh -p2016 apache@10.10.18.130 '/bin/sh /data/www/vhosts/WOStest3_ENV/update_env.sh' 需要设置shell远程免密码登 ...

  9. SaltStack远程执行shell脚本

    编辑文件fansik.sh 脚本内容: #!/bin/bash # Author: fansik # data: 2017年 09月 26日 星期二 :: CST touch /tmp/fansik. ...

随机推荐

  1. js判断是否安装flash player及当前版本 和 检查flash版本是否需要升级

    一.js检查flash版本升级 for (var i = 0, len = navigator.plugins.length; i < len; i++) { var plugin = navi ...

  2. Nginx作为负载均衡器upstream

    Nginx中与proxy模块结合使用的模块中,最常用的当属upstream模块.upstream模块可定义一个新的上下文,它包含了一组upstream服务器,这些服务器可能被赋予了不同的权重.不同的类 ...

  3. 利用 fdisk进行分区

    ):fdisk命令参数 p:打印分区表. n:新建一个新分区. d:删除一个新分区. q:退出不保存. w:退出且保存. 例子: 先看下磁盘: root@archiso ~ # lsblk 在这里对磁 ...

  4. 基于jquery hover图片遮罩层滑动

    分享一款基于jquery hover图片遮罩层滑动.这是一款仿腾讯课堂的鼠标悬停经过图片遮罩透明层滑动效果.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div clas ...

  5. 基于jQuery实现滚动新闻代码下载

    分享一款基于jQuery实现滚动新闻代码下载.这是一款基于bootstrup 3实现的响应式jQuery滚动新闻插件.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div ...

  6. tomcat 远程命令执行漏洞复现

    影响范围 Apache Tomcat 7.0.0 - 7.0.81 不受影响的版本 Apache Tomcat 8.x Apache Tomcat 9.x 漏洞分析 在Tomcat安装目录下的配置文件 ...

  7. [转]JAVA泛型通配符T,E,K,V区别,T以及Class<T>,Class<?>的区别

    原文地址:https://www.jianshu.com/p/95f349258afb 1. 先解释下泛型概念 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被 ...

  8. Mac OS X上搭建Apache、PHP、MySQL的Web服务器

    mac OS 系统太帅了,安装php的环境如此简单,大赞一个! 转载自http://jingyan.baidu.com/article/39810a23e1939fb636fda6a9.html 在M ...

  9. html绝对路径与相对路径

    文件,图片和html文档同一个目录的直接写文件名即可(相对路径). 工作中一般使用相对路径,项目放到服务器上部署不能保证绝对路径不出错.

  10. Linux0.11从开机到准备执行main函数的启动学习

    最近一直在看操作系统以及内核设计的东西,不确定自己有能力会参与到类似的开发之中,但是争取能自己改造这内核玩一下,然后按照Linux From Scratch那样的把改造后的系统编译运行就心满意足了.正 ...