JSch基本使用
JSch 是SSH2的一個純Java實現。它允許你連接到一個sshd 服務器,使用端口轉發,X11轉發,文件傳輸等等。你可以將它的功能集成到你自己的 程序中。同時該項目也提供一個J2ME版本用來在手機上直連SSHD服務器。
官網:http://www.jcraft.com/jsch/中有很多例子http://www.jcraft.com/jsch/examples/,這里先采用(已做修改)其中2個來進行簡單論述,希望對大家有所幫助。
本文采用的jsch版本是0.1.51. 下載地址:http://sourceforge.net/projects/jsch/files/jsch/0.1.54/jsch-0.1.54.zip/download。
本文采用的Linux操作系統是CentOS6.5.
TIPS: 查看Linux操作系統(內核)版本可以使用:uname -a; uname -r; cat /etc/issue; cat /etc/redhat-release等命令。
第一個例子:采用Java模擬shell操作。
這里涉及到幾個參數,會在下面的代碼中有所體現:
- USER:所連接的Linux主機登錄時的用戶名
- PASSWORD:登錄密碼
- HOST:主機地址
- DEFAULT_SSH_PROT=端口號,默認為22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
package
com.test.jsch;
/**
* This program enables you to connect to sshd server and get the shell prompt.
* You will be asked username, hostname and passwd.
* If everything works fine, you will get the shell prompt. Output may
* be ugly because of lacks of terminal-emulation, but you can issue commands.
*/
import
com.jcraft.jsch.JSch;
import
com.jcraft.jsch.Session;
import
com.jcraft.jsch.UserInfo;
import
com.jcraft.jsch.Channel;
public
class
Shell{
private
static
final
String USER=
"root"
;
private
static
final
String PASSWORD=
"********"
;
private
static
final
String HOST=
"localhost"
;
private
static
final
int
DEFAULT_SSH_PORT=
22
;
public
static
void
main(String[] arg){
try
{
JSch jsch=
new
JSch();
Session session = jsch.getSession(USER,HOST,DEFAULT_SSH_PORT);
session.setPassword(PASSWORD);
UserInfo userInfo =
new
UserInfo() {
@Override
public
String getPassphrase() {
System.out.println(
"getPassphrase"
);
return
null
;
}
@Override
public
String getPassword() {
System.out.println(
"getPassword"
);
return
null
;
}
@Override
public
boolean
promptPassword(String s) {
System.out.println(
"promptPassword:"
+s);
return
false
;
}
@Override
public
boolean
promptPassphrase(String s) {
System.out.println(
"promptPassphrase:"
+s);
return
false
;
}
@Override
public
boolean
promptYesNo(String s) {
System.out.println(
"promptYesNo:"
+s);
return
true
;
//notice here!
}
@Override
public
void
showMessage(String s) {
System.out.println(
"showMessage:"
+s);
}
};
session.setUserInfo(userInfo);
// It must not be recommended, but if you want to skip host-key check,
// invoke following,
// session.setConfig("StrictHostKeyChecking", "no");
//session.connect();
session.connect(
30000
);
// making a connection with timeout.
Channel channel=session.openChannel(
"shell"
);
// Enable agent-forwarding.
//((ChannelShell)channel).setAgentForwarding(true);
channel.setInputStream(System.in);
/*
// a hack for MS-DOS prompt on Windows.
channel.setInputStream(new FilterInputStream(System.in){
public int read(byte[] b, int off, int len)throws IOException{
return in.read(b, off, (len>1024?1024:len));
}
});
*/
channel.setOutputStream(System.out);
/*
// Choose the pty-type "vt102".
((ChannelShell)channel).setPtyType("vt102");
*/
/*
// Set environment variable "LANG" as "ja_JP.eucJP".
((ChannelShell)channel).setEnv("LANG", "ja_JP.eucJP");
*/
//channel.connect();
channel.connect(
3
*
1000
);
}
catch
(Exception e){
System.out.println(e);
}
}
}
|
運行結果:
1
2
3
4
5
6
|
promptYesNo:
The authenticity of host
'10.101.139.5'
can't be established.
RSA key fingerprint is 59:0f:32:fc:7b:54:3d:90:c0:ef:5a:6b:fb:11:55:e1.
Are you sure you want to
continue
connecting?
trueLast login: Thu Sep 29 18:40:56 2016 from 10.101.48.240
[root@hidden ~]
#
|
輸入ls查看:
1
2
3
4
5
6
7
|
(省略一些....)
[root@hidden ~]
# ls
ls
1.txt
install
.log.syslog vmware-tools-distrib 模板 文檔 桌面
anaconda-ks.cfg logs workspace 視頻 下載
install
.log util 公共的 圖片 音樂
[root@hidden ~]
#
|
這樣就和在原linux系統中一樣使用shell功能了。
如果需要跳過如下的檢測:
1
2
3
|
The authenticity of host
'10.101.139.5'
can't be established.
RSA key fingerprint is 59:0f:32:fc:7b:54:3d:90:c0:ef:5a:6b:fb:11:55:e1.
Are you sure you want to
continue
connecting?
|
只需要在程序中加入相應的代碼:
1
|
session.setConfig(
"StrictHostKeyChecking"
,
"no"
);
|
運行結果:
1
2
|
Last login: Thu Sep 29 18:39:18 2016 from 10.101.48.240
[root@hidden ~]
#
|
第二個例子:運行一條shell指令,這里就那“ls”做例子好了。
No more talk, show you the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
package
com.test.jsch;
import
com.jcraft.jsch.*;
import
java.io.*;
public
class
Exec{
private
static
final
String USER=
"root"
;
private
static
final
String PASSWORD=
"********"
;
private
static
final
String HOST=
"localhost"
;
private
static
final
int
DEFAULT_SSH_PORT=
22
;
public
static
void
main(String[] arg){
try
{
JSch jsch=
new
JSch();
Session session = jsch.getSession(USER,HOST,DEFAULT_SSH_PORT);
session.setPassword(PASSWORD);
// username and password will be given via UserInfo interface.
session.setUserInfo(
new
MyUserInfo());
session.connect();
String command=
"ls"
;
Channel channel=session.openChannel(
"exec"
);
((ChannelExec)channel).setCommand(command);
// X Forwarding
// channel.setXForwarding(true);
//channel.setInputStream(System.in);
channel.setInputStream(
null
);
//channel.setOutputStream(System.out);
//FileOutputStream fos=new FileOutputStream("/tmp/stderr");
//((ChannelExec)channel).setErrStream(fos);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
channel.connect();
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
;
}
try
{Thread.sleep(
1000
);}
catch
(Exception ee){}
}
channel.disconnect();
session.disconnect();
}
catch
(Exception e){
System.out.println(e);
}
}
private
static
class
MyUserInfo
implements
UserInfo{
@Override
public
String getPassphrase() {
System.out.println(
"getPassphrase"
);
return
null
;
}
@Override
public
String getPassword() {
System.out.println(
"getPassword"
);
return
null
;
}
@Override
public
boolean
promptPassword(String s) {
System.out.println(
"promptPassword:"
+s);
return
false
;
}
@Override
public
boolean
promptPassphrase(String s) {
System.out.println(
"promptPassphrase:"
+s);
return
false
;
}
@Override
public
boolean
promptYesNo(String s) {
System.out.println(
"promptYesNo:"
+s);
return
true
;
//notice here!
}
@Override
public
void
showMessage(String s) {
System.out.println(
"showMessage:"
+s);
}
}
}
|
運行結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
promptYesNo:The authenticity of host
'10.101.139.5'
can't be established.
RSA key fingerprint is 59:0f:32:fc:7b:54:3d:90:c0:ef:5a:6b:fb:11:55:e1.
Are you sure you want to
continue
connecting?
1.txt
anaconda-ks.cfg
install
.log
install
.log.syslog
logs
util
vmware-tools-distrib
workspace
公共的
模板
視頻
圖片
文檔
下載
音樂
桌面
exit
-status: 0
|
第二個例子相比於第一個例子來說將UserInfo采用static class的方式提取出來,這樣更直觀一點。
JSch是以多線程方式一下,所以代碼在connect后如果不disconnect channel和session,以及相關stream, 程序會一直等待,直到關閉。
需要注意的一個問題,相關的Stream和Channel是一定要關閉的,那么應該在什么時候來關?執行connect后,JSch接受客戶端結果需要一定的時間(以秒計),如果馬上關閉session就會發現什么都沒接受到或內容不全。
還有一點注意,使用shell時,看到執行后沒有結果,解決辦法是在命令行后加上”\n”字符,server端就認為是一條完整的命令了。
最后將第一個和第二個例子合並,並提取一些公用模塊,以便更好的理解和使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
package
com.test.jsch;
import
com.jcraft.jsch.*;
import
java.io.*;
import
java.util.concurrent.TimeUnit;
import
static
java.lang.String.format;
/**
* Created by hidden on 2016/9/29.
*/
public
class
SSHExecutor {
private
static
long
INTERVAL = 100L;
private
static
int
SESSION_TIMEOUT =
30000
;
private
static
int
CHANNEL_TIMEOUT =
3000
;
private
JSch jsch =
null
;
private
Session session =
null
;
private
SSHExecutor(SSHInfo sshInfo)
throws
JSchException {
jsch =
new
JSch();
session = jsch.getSession(sshInfo.getUser(),sshInfo.getHost(),sshInfo.getPort());
session.setPassword(sshInfo.getPassword());
session.setUserInfo(
new
MyUserInfo());
session.connect(SESSION_TIMEOUT);
}
/*
* 在這里修改訪問入口,當然可以把這個方法弄到SSHExecutor外面,這里是方便操作才這么做的
* */
public static SSHExecutor newInstance() throws JSchException {
SSHInfo sshInfo = new SSHInfo("root","******","locahost",22);
return new SSHExecutor(sshInfo);
}
/*
* 注意編碼轉換
* */
public long shell(String cmd, String outputFileName) throws JSchException, IOException, InterruptedException {
long start = System.currentTimeMillis();
Channel channel = session.openChannel("shell");
PipedInputStream pipeIn = new PipedInputStream();
PipedOutputStream pipeOut = new PipedOutputStream( pipeIn );
FileOutputStream fileOut = new FileOutputStream( outputFileName, true);
channel.setInputStream(pipeIn);
channel.setOutputStream(fileOut);
channel.connect(CHANNEL_TIMEOUT);
pipeOut.write(cmd.getBytes());
Thread.sleep( INTERVAL );
pipeOut.close();
pipeIn.close();
fileOut.close();
channel.disconnect();
return System.currentTimeMillis() - start;
}
public int exec(String cmd) throws IOException, JSchException, InterruptedException {
ChannelExec channelExec = (ChannelExec)session.openChannel( "exec" );
channelExec.setCommand( cmd );
channelExec.setInputStream( null );
channelExec.setErrStream( System.err );
InputStream in = channelExec.getInputStream();
channelExec.connect();
int res = -1;
StringBuffer buf = new StringBuffer( 1024 );
byte[] tmp = new byte[ 1024 ];
while ( true ) {
while ( in.available() > 0 ) {
int i = in.read( tmp, 0, 1024 );
if ( i < 0 ) break;
buf.append( new String( tmp, 0, i ) );
}
if ( channelExec.isClosed() ) {
res = channelExec.getExitStatus();
System.out.println( format( "Exit-status: %d", res ) );
break;
}
TimeUnit.MILLISECONDS.sleep(100);
}
System.out.println( buf.toString() );
channelExec.disconnect();
return res;
}
public Session getSession(){
return session;
}
public void close(){
getSession().disconnect();
}
/*
* SSH連接信息
* */
public static class SSHInfo{
private String user;
private String password;
private String host;
private int port;
public SSHInfo(String user, String password, String host, int port) {
this.user = user;
this.password = password;
this.host = host;
this.port = port;
}
public String getUser() {
return user;
}
public String getPassword() {
return password;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
}
/*
* 自定義UserInfo
* */
private
static
class
MyUserInfo
implements
UserInfo{
@Override
public
String getPassphrase() {
return
null
; }
@Override
public
String getPassword() {
return
null
; }
@Override
public
boolean
promptPassword(String s) {
return
false
; }
@Override
public
boolean
promptPassphrase(String s) {
return
false
; }
@Override
public
boolean
promptYesNo(String s) {
System.out.println(s);
System.out.println(
"true"
);
return
true
;
}
@Override
public
void
showMessage(String s) { }
}
}
|
測試代碼:
1
2
3
4
5
6
7
8
9
|
SSHExecutor ssh = SSHExecutor.newInstance();
System.out.println(
"================"
);
long
shell1 = ssh.shell(
"ls\n"
,
"C:\\Users\\hidden\\Desktop\\shell.txt"
);
long
shell2 = ssh.shell(
"pwd\n"
,
"C:\\Users\\hidden\\Desktop\\shell.txt"
);
System.out.println(
"shell 1 執行了"
+shell1+
"ms"
);
System.out.println(
"shell 2 執行了"
+shell2+
"ms"
);
System.out.println(
"================"
);
int
cmd1 = ssh.exec(
"ls\n"
);
ssh.close();
|
測試結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
The authenticity of host
'10.101.139.5'
can't be established.
RSA key fingerprint is 59:0f:32:fc:7b:54:3d:90:c0:ef:5a:6b:fb:11:55:e1.
Are you sure you want to
continue
connecting?
true
================
shell 1 執行了142ms
shell 2 執行了132ms
================
Exit-status: 0
1.txt
anaconda-ks.cfg
install
.log
install
.log.syslog
logs
util
vmware-tools-distrib
workspace
公共的
模板
視頻
圖片
文檔
下載
音樂
桌面
|
還有解釋查看一下左邊是否有個shell.txt以及shell.txt是否有相應的內容。