Apache Mina SSHD和Jsch:输入流总是0

时间:2016-08-04 08:54:07

标签: java inputstream jsch sshd apache-mina

我正在使用Jsch库测试简单的Apache Mina SSHD服务器。 Junit测试看起来像:

package com.ssh;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.sshd.SshServer;
import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.UserAuth;
import org.apache.sshd.server.auth.UserAuthPassword;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.session.ServerSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.ssh.util.EchoShellFactory;

public class SshServiceTest {

    @Rule
    public TemporaryFolder testFolder = new TemporaryFolder();

    private static final String USERNAME = "username";

    private static final String PASSWORD = "password";

    private static final String HOSTNAME = "localhost";

    private SshServer sshd;

    @Before
    public void prepare() throws IOException {
        setupSSHServer();
    }

    private void setupSSHServer() throws IOException {
        sshd = SshServer.setUpDefaultServer();
        sshd.setPort(22);
        sshd.setKeyPairProvider(
                new SimpleGeneratorHostKeyProvider(testFolder.newFile("hostkey.ser").getAbsolutePath()));

        List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<NamedFactory<UserAuth>>();
        userAuthFactories.add(new UserAuthPassword.Factory());
        sshd.setUserAuthFactories(userAuthFactories);

        sshd.setPasswordAuthenticator(new PasswordAuthenticator() {
            public boolean authenticate(String username, String password, ServerSession session) {
                return USERNAME.equals(username) && PASSWORD.equals(password);
            }
        });

        sshd.setShellFactory(new EchoShellFactory()); 
        sshd.start();
    }

    @Test
    public void testConnection() throws Exception {
        System.out.println("test started");

        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        JSch jsch = new JSch();
        Session session = jsch.getSession(USERNAME, HOSTNAME, 22);
        session.setPassword(PASSWORD);
        session.setConfig(config);
        session.connect();
        System.out.println("Connected");

        Channel channel = session.openChannel("exec");
        ((ChannelExec) channel).setCommand("pwd");

        ((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()) {
                System.out.println("exit-status: " + channel.getExitStatus());
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (Exception ee) {
            }
        }

        channel.disconnect();
        session.disconnect();
        System.out.println("DONE");

    }

    @After
    public void cleanup() throws InterruptedException {
        try {
            sshd.stop(true);
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

我的shell工厂看起来像:

package com.ssh.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;

import org.apache.sshd.common.Factory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;

public class EchoShellFactory implements Factory<Command> {

    public Command create() {
        return new EchoShell();
    }

    public static class EchoShell implements Command, Runnable {

        private InputStream in;
        private OutputStream out;
        private OutputStream err;
        private ExitCallback callback;
        private Environment environment;
        private Thread thread;

        public InputStream getIn() {
            return in;
        }

        public OutputStream getOut() {
            return out;
        }

        public OutputStream getErr() {
            return err;
        }

        public Environment getEnvironment() {
            return environment;
        }

        public void setInputStream(InputStream in) {
            this.in = in;
        }

        public void setOutputStream(OutputStream out) {
            this.out = out;
        }

        public void setErrorStream(OutputStream err) {
            this.err = err;
        }

        public void setExitCallback(ExitCallback callback) {
            this.callback = callback;
        }

        public void start(Environment env) throws IOException {
            environment = env;
            thread = new Thread(this, "EchoShell");
            thread.start();
        }

        public void destroy() {
            thread.interrupt();
        }

        public void run() {
            BufferedReader r = new BufferedReader(new InputStreamReader(in));
            try {
                for (;;) {
                    String s = r.readLine();
                    if (s == null) {
                        return;
                    }
                    out.write(("executed " + s + "\r\n").getBytes());
                    out.flush();
                    if ("exit".equals(s)) {
                        return;
                    }
                }
            } catch (InterruptedIOException e) {
                // Ignore
            } catch (Exception e) {
                System.out.println("Error executing EchoShell...");
            } finally {
                if (r != null) {
                    try {
                        r.close();
                    } catch (IOException e) {
                        // ignore
                    }
                }
                callback.onExit(0);
            }
        }
    }
}

在这种情况下,in.available()的值始终为“0”,而外观则永远运行。我必须手动停止该过程。当SSHD服务器启动时,我可以通过putty连接到它并执行伪命令。只有当我尝试使用Jsch lib连接到此服务器时,如上所示的输入流始终为0.我在很多地方搜索,但找不到什么错误。如果您对如何使其有效,请告诉我。

提前致谢。

1 个答案:

答案 0 :(得分:0)

我解决了这个问题。因为&#34; exec&#34;模式不是交互式的,程序认为执行没​​有完成。所以你需要使用&#34; shell&#34;模式而不是&#34; exec&#34;,但你需要添加&#34;退出&#34;或者&#34;退出&#34;命令后命令结束交互。