環境
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 :: from .
ls
cd /home/jenkins/workspace/ggservice
pwd
[[email protected] ~]# ls
bintray-sbt-rpm.repo tables_mysql_innodb.sql
[[email protected] ~]#
[[email protected] ~]# cd /home/jenkins/workspace/ggservice
[[email protected] ggservice]#
[[email protected] ggservice]# pwd
/home/jenkins/workspace/ggservice
[[email protected] ggservice]#
可以看出,連
[[email protected] ~]
這樣的指令提示符和輸入的指令都出來,我其實是不需要這個,我要的隻是結果。
②由于使用
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[];
while(true){
while(in.available()>){
int i=in.read(tmp, , );
if(i<)break;
System.out.print(new String(tmp, , i));
}
if(channel.isClosed()){
if(in.available()>) 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