我正在使用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.我在很多地方搜索,但找不到什么错误。如果您对如何使其有效,请告诉我。
提前致谢。
答案 0 :(得分:0)
我解决了这个问题。因为&#34; exec&#34;模式不是交互式的,程序认为执行没有完成。所以你需要使用&#34; shell&#34;模式而不是&#34; exec&#34;,但你需要添加&#34;退出&#34;或者&#34;退出&#34;命令后命令结束交互。