java程序使用Jsch 实现 ssh连接

Jsch

一、简介

JSch是SSH2的纯Java实现 。

JSch允许您连接到sshd服务器并使用端口转发,X11转发,文件传输等,并且您可以将其功能集成到您自己的Java程序中。JSch已获得BSD样式许可

为什么用选择 Jsch?

最初,我们开发此产品的动机是让我们纯Java X服务器 WiredX的用户享受安全的X会话。因此,我们的工作主要针对实现X11转发的SSH2协议。但是,当然,我们现在也对添加其他功能(例如端口转发,文件传输,终端仿真等)感兴趣。

SSH2

不用说,SSH支持安全的远程登录,安全的文件传输以及安全的TCP / IP和X11转发。它可以自动加密,认证和压缩传输的数据。SSH协议有两个不兼容的版本:SSH1和SSH2。发明SSH2的目的是避免有关RSA的专利问题(RSA专利已过期),并解决SSH1所存在的某些数据完整性问题,还有其他一些技术原因。SSH2协议已在IETF Secure Shell工作组上进行了标准化, 有关SSH2协议的草案可从Web上获得。在开发JSch时,我们现在参考以下文档:

使用JSch的应用程序

二、Jsch的使用

API:http://epaul.github.io/jsch-documentation/javadoc/com/jcraft/jsch/JSch.html

1、连接到服务器

public class JSchDemo {

   private String ipAddress;   //主机ip
   private String username;   // 账号
   private String password;   // 密码
   private int port;  // 端口号

   Session session;

   public JSchDemo(String ipAddress, String username, String password, int port) {
      this.ipAddress = ipAddress;
      this.username = username;
      this.password = password;
      this.port = port;
   }

   /**
    *  连接到指定的ip
    */
   public void connect() {
      try {
         JSch jsch = new JSch();
         if (port < 0 || port > 65535){
            //连接服务器,如果端口号错误,采用默认端口
            session = jsch.getSession(username, ipAddress);
         }else {
            session = jsch.getSession(username, ipAddress, port);
         }
         //设置登录主机的密码
         session.setPassword(password);
         //如果服务器连接不上,则抛出异常
         if (session == null) {
            throw new Exception("session is null");
         }
         //设置首次登录跳过主机检查
         session.setConfig("StrictHostKeyChecking", "no");
         //设置登录超时时间
         session.connect(3000);
      } catch (Exception e) {
         log.error(e.getMessage(),e);
      }

   }
}

在这里插入图片描述

一个 Session 表示一个与SSH服务器的连接。一个 Session 可以包含多种多样的 Channel ,并且创建openChannel(java.lang.String)

一个 session 被一个 connect() 打开和被一个 disconnect() 关闭。

事实上一个 Session 实现 Runnable 接口 是一个实现细节。

关于Session的使用,创建连接后这个session是一直可用的,所以不需要关闭。由Session中open的Channel在使用后应该关闭。


2、执行命令

/**
 * 执行相关的命令(交互式)
 * @param command
 * @return
 */
public int execute(String command) {
    int returnCode = 0;
    ChannelShell channel = null;
    PrintWriter printWriter = null;
    BufferedReader input = null;
    stdout = new Vector<String>();
    try {
        //建立交互式通道
        channel = (ChannelShell) session.openChannel("shell");
        channel.connect();

        //获取输入
        InputStreamReader inputStreamReader = new InputStreamReader(channel.getInputStream());
        input = new BufferedReader(inputStreamReader);

        //输出
        printWriter = new PrintWriter(channel.getOutputStream());
        printWriter.println(command);
        printWriter.println("exit");
        printWriter.flush();
        log.info("The remote command is: ");
        String line;
        while ((line = input.readLine()) != null) {
            stdout.add(line);
            System.out.println(line);
        }
    } catch (Exception e) {
        log.error(e.getMessage(),e);
        return -1;
    }finally {
        IoUtil.close(printWriter);
        IoUtil.close(input);
        if (channel != null) {
            //关闭通道
            channel.disconnect();
        }
    }
    return returnCode;
}

public void close(){
    if (session != null) {
        session.disconnect();
    }
}

在这里插入图片描述在这里插入图片描述

ChannelShell和ChannelExec区别?

参考:https://blog.csdn.net/u013066244/article/details/70911585

ChannelShell

对于ChannelShell,以输入流的形式,提供命令和输入这些命令,这就像在本地计算机上使用交互式shell(它通常用于:交互式使用)

ChannelExec

对于ChannelExec,在调用connect()方法之前这个命令提供了setCommand()方法,并且这些命令作为输入将以输入流的形式被发送出去。(通常,你只能有调用setCommand()方法一次,多次调用只有最后一次生效),但是你可以使用普通shell的分隔符(&,&&,|,||,; , \n, 复合命令)来提供多个命令。这就像在你本机上执行一个shell脚本一样(当然,如果一个命令本身就是个交互式shell,这样就像ChannelShell)

明显:使用命令通道更容易,因为您不需要处理命令提示符。

/**
 * 执行相关的命令(输入式)
 * @param command
 * @return
 */
 public int execute(String command) {
     int returnCode = 0;
     ChannelExec channel = null;
     PrintWriter printWriter = null;
     BufferedReader input = null;
     try {
         channel = (ChannelExec) session.openChannel("exec");
         channel.setCommand(command);
         InputStream in = channel.getInputStream();
         channel.connect();

         BufferedReader inputReader = new BufferedReader(new InputStreamReader(in, "GBK"));
         String inputLine;
         while ((inputLine = inputReader.readLine()) != null) {
             System.out.println(inputLine);
         }
         channel.disconnect();
         session.disconnect();
     } catch (Exception e) {
         log.error(e.getMessage(), e);
         return -1;
     } finally {
         IoUtil.close(printWriter);
         IoUtil.close(input);
         if (channel != null) {
             //关闭通道
             channel.disconnect();
         }
         if (session != null) {
             session.disconnect();
         }
     }
     return returnCode;
 }

3、利用JSch实现SFTP下载、上传文件

/**
 *	从SFTP服务器下载文件 
*/
private static void sftp_put(Session session, String uploadFileName) throws Exception {  
    Channel channel = null;  
    try {  
        //创建sftp通信通道  
        channel = (Channel) session.openChannel("sftp");  
        channel.connect(1000);  
        ChannelSftp sftp = (ChannelSftp) channel;  


        //进入服务器指定的文件夹  
        sftp.cd("/root");  

        //列出服务器指定的文件列表  
        Vector v = sftp.ls("/");  
        for(int i=0;i<v.size();i++){  
            System.out.println(v.get(i));  
        }  

        //以下代码实现从本地上传一个文件到服务器,如果要实现下载,对换以下流就可以了  
        OutputStream outstream = sftp.put(uploadFileName);  
        InputStream instream = new FileInputStream(new File("C:\\aa.txt"));  

        byte b[] = new byte[1024];  
        int n;  
        while ((n = instream.read(b)) != -1) {  
            outstream.write(b, 0, n);  
        }  

        outstream.flush();  
        outstream.close();  
        instream.close();  
    } catch (Exception e) {  
        e.printStackTrace();  
    } finally {  
        session.disconnect();  
        channel.disconnect();  
    }  
}  

/* 
     * 从SFTP服务器下载文件 
     * @param ftpHost SFTP IP地址 
     * @param ftpUserName SFTP 用户名 
     * @param ftpPassword SFTP用户名密码 
     * @param ftpPort SFTP端口 
     * @param ftpPath SFTP服务器中文件所在路径 格式: ftptest/aa 
     * @param localPath 下载到本地的位置 格式:H:/download 
     * @param fileName 文件名称 
     */  
public static void downloadSftpFile(String ftpHost, String ftpUserName,  
                                    String ftpPassword, int ftpPort, String ftpPath, String localPath,  
                                    String fileName) throws JSchException {  
    Session session = null;  
    Channel channel = null;  

    JSch jsch = new JSch();  
    session = jsch.getSession(ftpUserName, ftpHost, ftpPort);  
    session.setPassword(ftpPassword);  
    session.setTimeout(100000);  
    Properties config = new Properties();  
    config.put("StrictHostKeyChecking", "no");  
    session.setConfig(config);  
    session.connect();  

    channel = session.openChannel("sftp");  
    channel.connect();  
    ChannelSftp chSftp = (ChannelSftp) channel;  

    String ftpFilePath = ftpPath + "/" + fileName;  
    String localFilePath = localPath + File.separatorChar + fileName;  

    try {  
        chSftp.get(ftpFilePath, localFilePath);  
    } catch (Exception e) {  
        e.printStackTrace();  
    } finally {  
        chSftp.quit();  
        channel.disconnect();  
        session.disconnect();  
    }  

}  
}

参考链接:https://blog.csdn.net/u013467442/article/details/69642148


三、Jsch的封装,sshxcute

面向 Java 开发与测试人员的远程执行 Linux/UNIX 系统上任务的框架 — sshxcute

JSch 是 SSH2 的一个纯 Java 实现。它可以连接到一个 sshd 服务器,使用端口转发,X11 转发,文件传输等等。但是这个类库毕竟偏向底层,上手与实际运行起来不太方便,sshxcute 框架正是基于 JSch 封装的,提供了更为便捷的 API 借口,更加灵活实用的功能,从而可以让开发与测试人员更加得心应手的使用。sshxcute 是一个框架,它允许工程师利用 Java 代码通过 SSH 连接远程执行 Linux/UNIX 系统上的命令或者脚本,这种方式不管是针对软件测试还是系统部署,都简化了自动化测试与系统环境部署的步骤。

框架源码:https://gitee.com/charkeyqk/sshxcute

最后一次更新在 2014-03-01

使用:https://www.ibm.com/developerworks/cn/opensource/os-sshxcute/#ibm-pcon


四、Hutool工具类

发现 hutool 对Jsch做了封装,使用起来更加简单方便,不需要自己再去实现了。

https://hutool.cn/docs/#/extra/Jsch%E5%B0%81%E8%A3%85/Jsch%E5%B7%A5%E5%85%B7-JschUtil

使用

引入jsch

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.54</version>
</dependency>

说明 截止本文档撰写完毕,jsch的最新版为0.1.54,理论上应引入的版本应大于或等于此版本。

使用

ssh连接到远程主机
//新建会话,此会话用于ssh连接到跳板机(堡垒机),此处为10.1.1.1:22
Session session = JschUtil.getSession("10.1.1.1", 22, "test", "123456");
端口映射
//新建会话,此会话用于ssh连接到跳板机(堡垒机),此处为10.1.1.1:22
Session session = JschUtil.getSession("10.1.1.1", 22, "test", "123456");

// 将堡垒机保护的内网8080端口映射到localhost,我们就可以通过访问http://localhost:8080/访问内网服务了
JschUtil.bindPort(session, "172.20.12.123", 8080, 8080);
其它方法
  • generateLocalPort 生成一个本地端口(从10001开始尝试,找到一个未被使用的本地端口)
  • unBindPort 解绑端口映射
  • openAndBindPortToLocal 快捷方法,将连接到跳板机和绑定远程主机端口到本地使用一个方法搞定
  • close 关闭SSH会话
  • 1
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值