jsch中ChannelShell与ChannelExec的区别及说明

 更新时间:2023年07月11日 09:08:27   作者:山鬼谣me  
这篇文章主要介绍了jsch中ChannelShell与ChannelExec的区别及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

环境

  • jdk:java7
  • 操作系统: win7

因为框架jsch比较老,所以对java版本要求好低。

分析

框架jsch我就不说了,很老的框架,现在也不更新了。

官网:http://www.jcraft.com/jsch/

最近在用jsch中的ChannelShell时,遇到问题:

①这个方法会返回命令提示符

很烦;

比如我要执行下面几个命令:

        ChannelShell channel = (ChannelShell) session.openChannel("shell");
        channel.connect();
        InputStream inputStream = channel.getInputStream();
        OutputStream outputStream = channel.getOutputStream();
        String cmd = "ls \n\r";
        outputStream.write(cmd.getBytes());
        String cmd2 = "cd /home/jenkins/workspace/ggservice \n\r";
        outputStream.write(cmd2.getBytes());
        String cmd3 = "pwd \n\r";
        outputStream.write(cmd3.getBytes());
        outputStream.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
        String msg = null;
        while((msg = in.readLine())!=null){
            System.out.println(msg);
        }
        in.close();

得到的结果是:

Last login: Fri Apr 28 15:07:22 2017 from 192.168.52.63

ls 

cd /home/jenkins/workspace/ggservice 

pwd 

[root@master01 ~]# ls 
bintray-sbt-rpm.repo tables_mysql_innodb.sql
[root@master01 ~]# 
[root@master01 ~]# cd /home/jenkins/workspace/ggservice 
[root@master01 ggservice]# 
[root@master01 ggservice]# pwd 
/home/jenkins/workspace/ggservice
[root@master01 ggservice]# 

可以看出,连[root@master01 ~]这样的命令提示符和输入的命令都出来,我其实是不需要这个,我要的只是结果。

②由于使用BufferedReader的readLine()方法

结果会产生阻塞。

BufferedReader in = new BufferedReader(new InputStreamReader(inputStream)); String msg = null;
while((msg = in.readLine())!=null){//当所有的命令都执行完毕后,就会产生阻塞
    System.out.println(msg);
}
in.close();

如下图:

这里写图片描述

为什么会这样呢?

因为我们建立的是shell管道,并且我们又使用readLine方法,当命令全部执行完毕后,远程端并不知道执行完毕,还在等待接受数据,所以呢reandLine就一直阻塞在那里。

即便你换成read方法还是一样的,因为shell管道本身就是交互模式的。

要想停止,有两种方式

①人为的发送一个exit命令,告诉程序本次交互结束啦

②使用字节流中的available方法,来获取数据的总大小,然后循环去读。

  • ①代码:
        InputStream inputStream = channel.getInputStream();//从远程端到达的所有数据都能从这个流中读取到
        OutputStream outputStream = channel.getOutputStream();//写入该流的所有数据都将发送到远程端。
        //使用PrintWriter流的目的就是为了使用println这个方法
        //好处就是不需要每次手动给字符串加\n
        PrintWriter printWriter = new PrintWriter(outputStream);
        String cmd = "ls";
        printWriter.println(cmd);
        String cmd2 = "cd /home/jenkins/workspace/ggservice";
        printWriter.println(cmd2);
        String cmd3 = "ls";
        printWriter.println(cmd3);
        printWriter.println("exit");//加上个就是为了,结束本次交互
        printWriter.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream));
String msg = null;
        while((msg = in.readLine())!=null){
            System.out.println(msg);
        }
        in.close();
  • ②代码:
...代码省略 ...
ChannelShell channel = (ChannelShell) session.openChannel("shell");
channel.connect();
//从远程端到达的所有数据都能从这个流中读取到
InputStream in = channel.getInputStream();
//写入该流的所有数据都将发送到远程端。
OutputStream outputStream = channel.getOutputStream();
byte[] tmp=new byte[1024];
while(true){
  while(in.available()>0){
    int i=in.read(tmp, 0, 1024);
    if(i<0)break;
    System.out.print(new String(tmp, 0, i));
  }
  if(channel.isClosed()){
    if(in.available()>0) continue;
    System.out.println("exit-status: "+channel.getExitStatus());
    break;
  }
}

这样就不会阻塞啦

最后我就去查ChannelShell和ChannelExec区别

ChannelShell

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

ChannelExec

对于ChannelExec,在调用connect()方法之前这个命令提供了setCommand()方法,

并且这些命令作为输入将以输入流的形式被发送出去。

(通常,你只能有调用setCommand()方法一次,多次调用只有最后一次生效),

但是你可以使用普通shell的分隔符(&,&&,|,||,; , \n, 复合命令)来提供多个命令。

这就像在你本机上执行一个shell脚本一样(当然,如果一个命令本身就是个交互式shell,这样就像ChannelShell)

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

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

参考链接:

http://stackoverflow.com/a/6771417/6952713

http://stackoverflow.com/a/6266308/6952713

相关文章

  • 详解Java中的四种引用类型(强软弱虚)

    详解Java中的四种引用类型(强软弱虚)

    Java中的引用类型主要分为四种,分别是强引用、软引用、弱引用和虚引用,这篇文章主要为大家详细介绍了四者的使用与区别,需要的小伙伴可以参考下
    2023-10-10
  • 使用Spring动态修改bean属性的key

    使用Spring动态修改bean属性的key

    这篇文章主要介绍了使用Spring动态修改bean属性的key方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java开发微信Navicat支付完整版

    Java开发微信Navicat支付完整版

    这篇文章主要介绍了Java开发微信Navicat支付完整版,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • java.lang.Instrument 代理Agent使用详细介绍

    java.lang.Instrument 代理Agent使用详细介绍

    这篇文章主要介绍了java.lang.Instrument 代理Agent使用详细介绍的相关资料,附有实例代码,帮助大家学习参考,需要的朋友可以参考下
    2016-11-11
  • JVM分配和回收堆外内存的方式与注意点

    JVM分配和回收堆外内存的方式与注意点

    JVM启动时分配的内存称为堆内存,与之相对的,在代码中还可以使用堆外内存,比如Netty,广泛使用了堆外内存,下面这篇文章主要给大家介绍了关于JVM分配和回收堆外内存的方式与注意点,需要的朋友可以参考下
    2022-07-07
  • java正则表达式校验日期格式实例代码

    java正则表达式校验日期格式实例代码

    如果使用得当,正则表达式是匹配各种模式的强大工具,下面这篇文章主要给大家介绍了关于java正则表达式校验日期格式的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • Servlet实现简单的用户登录功能实例代码

    Servlet实现简单的用户登录功能实例代码

    这篇文章主要给大家介绍了关于利用Servlet实现简单的用户登录功能的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Spring高级之注解@PropertySource的原理

    Spring高级之注解@PropertySource的原理

    这篇文章主要介绍了Spring高级之注解@PropertySource的原理,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • jdk动态代理源码分析过程

    jdk动态代理源码分析过程

    这篇文章主要介绍了jkd动态代理源码分析过程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • Spring中基于xml的AOP实现详解

    Spring中基于xml的AOP实现详解

    这篇文章主要介绍了Spring中基于xml的AOP实现详解,基于xml与基于注解的AOP本质上是非常相似的,都是需要封装横切关注点,封装到切面中,然后把横切关注点封装为一个方法,再把该方法设置为当前的一个通知,再通过切入点表达式定位到横切点就可以了,需要的朋友可以参考下
    2023-09-09

最新评论