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是否有相應的內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章