环境
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

————————————————
版权声明:本文为CSDN博主「山鬼谣me」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013066244/article/details/70911585