jsch中ChannelShell與ChannelExec的區(qū)別及說明
環(huán)境
- jdk:java7
- 操作系統(tǒng): win7
因?yàn)榭蚣?code>jsch比較老,所以對(duì)java版本要求好低。
分析
框架jsch我就不說了,很老的框架,現(xiàn)在也不更新了。
官網(wǎng):http://www.jcraft.com/jsch/
最近在用jsch中的ChannelShell時(shí),遇到問題:
①這個(gè)方法會(huì)返回命令提示符
很煩;
比如我要執(zhí)行下面幾個(gè)命令:
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();得到的結(jié)果是:
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 ~]這樣的命令提示符和輸入的命令都出來,我其實(shí)是不需要這個(gè),我要的只是結(jié)果。
②由于使用BufferedReader的readLine()方法
結(jié)果會(huì)產(chǎn)生阻塞。
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream)); String msg = null;
while((msg = in.readLine())!=null){//當(dāng)所有的命令都執(zhí)行完畢后,就會(huì)產(chǎn)生阻塞
System.out.println(msg);
}
in.close();如下圖:

為什么會(huì)這樣呢?
因?yàn)槲覀兘⒌氖?code>shell管道,并且我們又使用readLine方法,當(dāng)命令全部執(zhí)行完畢后,遠(yuǎn)程端并不知道執(zhí)行完畢,還在等待接受數(shù)據(jù),所以呢reandLine就一直阻塞在那里。
即便你換成read方法還是一樣的,因?yàn)?code>shell管道本身就是交互模式的。
要想停止,有兩種方式
①人為的發(fā)送一個(gè)exit命令,告訴程序本次交互結(jié)束啦
②使用字節(jié)流中的available方法,來獲取數(shù)據(jù)的總大小,然后循環(huán)去讀。
- ①代碼:
InputStream inputStream = channel.getInputStream();//從遠(yuǎn)程端到達(dá)的所有數(shù)據(jù)都能從這個(gè)流中讀取到
OutputStream outputStream = channel.getOutputStream();//寫入該流的所有數(shù)據(jù)都將發(fā)送到遠(yuǎn)程端。
//使用PrintWriter流的目的就是為了使用println這個(gè)方法
//好處就是不需要每次手動(dòng)給字符串加\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");//加上個(gè)就是為了,結(jié)束本次交互
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();
//從遠(yuǎn)程端到達(dá)的所有數(shù)據(jù)都能從這個(gè)流中讀取到
InputStream in = channel.getInputStream();
//寫入該流的所有數(shù)據(jù)都將發(fā)送到遠(yuǎn)程端。
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;
}
}這樣就不會(huì)阻塞啦
最后我就去查ChannelShell和ChannelExec區(qū)別
ChannelShell
對(duì)于ChannelShell,以輸入流的形式,提供命令和輸入這些命令,這就像在本地計(jì)算機(jī)上使用交互式shell(它通常用于:交互式使用)
ChannelExec
對(duì)于ChannelExec,在調(diào)用connect()方法之前這個(gè)命令提供了setCommand()方法,
并且這些命令作為輸入將以輸入流的形式被發(fā)送出去。
(通常,你只能有調(diào)用setCommand()方法一次,多次調(diào)用只有最后一次生效),
但是你可以使用普通shell的分隔符(&,&&,|,||,; , \n, 復(fù)合命令)來提供多個(gè)命令。
這就像在你本機(jī)上執(zhí)行一個(gè)shell腳本一樣(當(dāng)然,如果一個(gè)命令本身就是個(gè)交互式shell,這樣就像ChannelShell)
明顯:使用命令通道更容易,因?yàn)槟恍枰幚砻钐崾痉?/p>
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
參考鏈接:
相關(guān)文章
Java基于Socket的文件傳輸實(shí)現(xiàn)方法
這篇文章主要介紹了Java基于Socket的文件傳輸實(shí)現(xiàn)方法,結(jié)合實(shí)例分析了Java使用Socket實(shí)現(xiàn)文件傳輸?shù)慕⑦B接、發(fā)送與接收消息、文件傳輸?shù)认嚓P(guān)技巧,需要的朋友可以參考下2015-12-12
Redis有效時(shí)間設(shè)置以及時(shí)間過期處理操作
這篇文章主要介紹了Redis有效時(shí)間設(shè)置以及時(shí)間過期處理操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11
java中 Map<String,Object>用法(示例代碼整合)
Java中Map<String, Object>是參數(shù)化接口,用于存儲(chǔ)鍵值對(duì)(鍵為String,值為Object),適用于動(dòng)態(tài)數(shù)據(jù)存儲(chǔ)、配置信息及JSON處理,需注意類型轉(zhuǎn)換和空指針異常,下面通過示例代碼給大家介紹java中 Map<String,Object>用法,感興趣的朋友一起看看吧2025-07-07
Idea連接數(shù)據(jù)庫并執(zhí)行SQL語句的方法示例
這篇文章主要介紹了Idea連接數(shù)據(jù)庫并執(zhí)行SQL語句的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Spring Boot中擴(kuò)展XML請(qǐng)求與響應(yīng)的支持詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot中擴(kuò)展XML請(qǐng)求與響應(yīng)的支持的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09
java優(yōu)先隊(duì)列PriorityQueue中Comparator的用法詳解
這篇文章主要介紹了java優(yōu)先隊(duì)列PriorityQueue中Comparator的用法詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
SpringMVC的REST風(fēng)格的四種請(qǐng)求方式總結(jié)
下面小編就為大家?guī)硪黄猄pringMVC的REST風(fēng)格的四種請(qǐng)求方式總結(jié)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-08-08
SpringBoot集成內(nèi)存數(shù)據(jù)庫Sqlite的實(shí)踐
sqlite這樣的內(nèi)存數(shù)據(jù)庫,小巧可愛,做小型服務(wù)端演示程序,非常好用,本文主要介紹了SpringBoot集成Sqlite,具有一定的參考價(jià)值,感興趣的可以了解一下2021-09-09

