关键词搜索

源码搜索 ×
×

JSch基本使用

发布2016-09-29浏览42408次

详情内容


欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


欢迎跳转到本文的原文链接:https://honeypps.com/java/jsch-quick-start/

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
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);
        }
    }
}

    运行结果:

    promptYesNo:
    The authenticity of host 'xx.xx.xx.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 xx.xx.xx.240
    [root@hidden ~]# 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输入ls查看:

    (省略一些....)
    [root@hidden ~]# ls
    ls
    1.txt            install.log.syslog  vmware-tools-distrib  模板  文档  桌面
    anaconda-ks.cfg  logs                workspace             视频  下载
    install.log      util                公共的                图片  音乐
    [root@hidden ~]# 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这样就和在原linux系统中一样使用shell功能了。

    如果需要跳过如下的检测:

    The authenticity of host 'xx.xx.xx.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
    • 2
    • 3

    只需要在程序中加入相应的代码:

    session.setConfig("StrictHostKeyChecking", "no");
    
    • 1

    运行结果:

    Last login: Thu Sep 29 18:39:18 2016 from xx.xx.xx.240
    [root@hidden ~]# 
    
    • 1
    • 2

    第二个例子:运行一条shell指令,这里就那“ls”做例子好了。

    No more talk, show you the code:

    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
    • 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

    运行结果:

    promptYesNo:The authenticity of host 'xx.xx.xx.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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    第二个例子相比于第一个例子来说将UserInfo采用static class的方式提取出来,这样更直观一点。

    JSch是以多线程方式一下,所以代码在connect后如果不disconnect channel和session,以及相关stream, 程序会一直等待,直到关闭。

    需要注意的一个问题,相关的Stream和Channel是一定要关闭的,那么应该在什么时候来关?执行connect后,JSch接受客户端结果需要一定的时间(以秒计),如果马上关闭session就会发现什么都没接受到或内容不全。

    还有一点注意,使用shell时,看到执行后没有结果,解决办法是在命令行后加上"\n"字符,server端就认为是一条完整的命令了。

    最后将第一个和第二个例子合并,并提取一些公用模块,以便更好的理解和使用:

    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/9https://cdn.jxasp.com:9143/image/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) { }
        }
    }
    
    
      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
    • 151

    测试代码:

            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

    测试结果:

    The authenticity of host 'xx.xx.xx.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
    公共的
    模板
    视频
    图片
    文档
    下载
    音乐
    桌面
    
    • 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

    还有解释查看一下左边是否有个shell.txt以及shell.txt是否有相应的内容。

    欢迎跳转到本文的原文链接:https://honeypps.com/java/jsch-quick-start/


    欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《RabbitMQ实战指南》,同时欢迎关注笔者的微信公众号:朱小厮的博客。


    相关技术文章

    点击QQ咨询
    开通会员
    返回顶部
    ×
    微信扫码支付
    微信扫码支付
    确定支付下载
    请使用微信描二维码支付
    ×

    提示信息

    ×

    选择支付方式

    • 微信支付
    • 支付宝付款
    确定支付下载