我正在尝试使用jcraft版本0.1.52通过ssh jump-host proxy连接到SFTP位置。但是," 连接被外国主机关闭"我的代码中的异常。我花了足够的时间查看文档,但无法弄清问题是什么
2016-11-18 14:53:14,091 44977 [main] ERROR c.w.v.r.ftp.JschSftpConnect -
- com.jcraft.jsch.JSchException: connection is closed by foreign host
at com.jcraft.jsch.Session.connect(Session.java:269)
at com.jcraft.jsch.Session.connect(Session.java:183)
at com.x.y.ftp.JschSftpConnect.connect(JschSftpConnect.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
私钥没有问题,因为我可以通过unix命令连接到sftp服务器。
sftp -o UserKnownHostsFile=/dev/null
-o StrictHostKeyChecking=no
-i /path/to/host/private-key-file
-o 'ProxyCommand=ssh
-o UserKnownHostsFile=/dev/null
-o StrictHostKeyChecking=no
-i /path/to/jumphost/private-key-file
-l jumphostuser jump.host.com nc sftp.host.com 22'
代码:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;
import org.apache.commons.lang3.exception.ExceptionUtils;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SocketFactory;
public class JschSftpConnect {
public static void main(String args[]) {
String sftpHostKeyFilePath = "/path/to/host/private-key-file";
String sftpHost="sftp.host.com";
String sftpUser="user";
String proxyHostName="jump.host.com";
String proxyKeyPath ="/path/to/jumphost/private-key-file";
String proxyUserName="jumphostuser";
log.debug("Executing JSCH code.....");
try {
JSch jsch = new JSch();
Path path = FileSystems.getDefault().getPath(sftpHostKeyFilePath);
byte[] filearray = Files.readAllBytes(path);
jsch.addIdentity("ID", filearray, null, null);
Session session = jsch.getSession(sftpUser, sftpHost, 22);
Properties props = new Properties();
props.put("StrictHostKeyChecking", "no");
session.setConfig(props);
String command = "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i "
+ localKeyFileDirectoryName + proxyKey + " -l " + proxyUserName + " " + proxyHostName
+ " nc %h %p";
session.setProxy(new JumpHostProxyCommand(command));
log.debug("Connecting session .......................");
session.connect();
log.debug("Session openend .......................");
Channel ch = session.openChannel("sftp");
ch.connect();
log.debug("SFTP channel connected .......................");
ChannelSftp channelSftp = (ChannelSftp) ch;
channelSftp.cd("/");
log.debug("Working directory is / .......................");
byte[] buffer = new byte[1024];
BufferedInputStream bis = new BufferedInputStream(channelSftp.get("/some_file_.psv"));
File newFile = new File("some_file_.psv");
OutputStream os = new FileOutputStream(newFile);
BufferedOutputStream bos = new BufferedOutputStream(os);
int readCount;
// System.out.println("Getting: " + theLine);
while ((readCount = bis.read(buffer)) > 0) {
// System.out.println("Writing: ");
bos.write(buffer, 0, readCount);
}
log.debug("File should have been written / .......................");
while (session != null) {
System.out.println("Killing the session");
session.disconnect();
bis.close();
bos.close();
System.exit(0);
}
} catch (Exception e) {
log.error(ExceptionUtils.getStackTrace(e));
}
}
}
class JumpHostProxyCommand implements Proxy {
String command;
Process p = null;
InputStream in = null;
OutputStream out = null;
public JumpHostProxyCommand(String command) {
this.command = command;
}
public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws Exception {
String cmd = command.replace("%h", host);
cmd = cmd.replace("%p", new Integer(port).toString());
p = Runtime.getRuntime().exec(cmd);
log.debug("Process returned by proxy command {} , {}", command, p);
in = p.getInputStream();
log.debug("Input stream returned by proxy {}", in);
out = p.getOutputStream();
log.debug("Output stream returned by proxy {}", out);
}
public Socket getSocket() {
return null;
}
public InputStream getInputStream() {
return in;
}
public OutputStream getOutputStream() {
return out;
}
public void close() {
try {
if (p != null) {
p.getErrorStream().close();
p.getOutputStream().close();
p.getInputStream().close();
p.destroy();
p = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
如果有人可以提供帮助,真的很感激。谢谢!
答案 0 :(得分:0)
这里的方法对我来说很好。
基本上它是一条隧道 你的sftp主机。它通过jumphost或隧道主机创建一个到sftp主机的隧道,并通过sftpChannel从这个隧道的" localhost"中获取文件。港口(2222)。 我通过两个ssh主机测试了它。它工作正常。
import com.jcraft.jsch.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
public class JschSftpConnect {
public static final Logger log = LoggerFactory.getLogger(JschSftpConnect.class);
public static final com.jcraft.jsch.Logger sshLogger = new com.jcraft.jsch.Logger() {
public boolean isEnabled(int level) {
return true;
}
public void log(int level, String message) {
switch (level) {
case 0:
log.debug(message);
break;
case 1:
log.info(message);
break;
case 2:
log.warn(message);
break;
case 3:
log.error(message);
break;
case 4:
log.error(message);
break;
default:
break;
}
}
};
public static void main(final String args[]) {
final String tunnelHostKey = "keyfile";
final String tunnelHost = "sshTunnelHost";
final String tunnelHostUser = "tunnelsshuser";
final String sftpKey = "sftpKey";
final String sftpHost = "sftpHost";
final String sftpUser = "sftpuser";
if (args.length >= 2) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Session tunnelSesssion =
createSession(tunnelHostKey, tunnelHost, tunnelHostUser,22);
tunnelSesssion.setPortForwardingL
(2222,sftpHost,22);
Session sftpSession =
createSession(sftpKey, "localhost", sftpUser,2222);
ChannelSftp sftpChannel =
getChannel(sftpSession);
if (args.length >= 2) {
sftpChannel.cd(args[0]);
log.debug("Working directory is " + sftpChannel.pwd());
getFileFromSftp(sftpChannel, args[1], args.length == 3 ? args[2] : args[1]);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}).start();
} else {
log.info("usage: java JschSftpConnect -cp ... <sftp dir> <sftp infile> <optional out file>");
System.exit(-1);
}
}
private static Session createSession(
String keyFile, String host, String user,int port
) throws IOException, JSchException {
JSch jsch = new JSch();
JSch.setLogger(sshLogger);
Path path = FileSystems.getDefault().getPath(keyFile);
byte[] filearray = Files.readAllBytes(path);
jsch.addIdentity("ID", filearray, null, null);
Session session = jsch.getSession(user, host, port);
Properties props = new Properties();
props.put("StrictHostKeyChecking", "no");
session.setConfig(props);
session.setTimeout(1000);
session.connect();
if (!session.isConnected()) {
throw new IOException("Session not connected");
}
return session;
}
private static ChannelSftp getChannel(Session session)throws IOException, JSchException{
Channel ch = session.openChannel("sftp");
log.debug("SFTP channel connected .......................");
ChannelSftp channelSftp = (ChannelSftp) ch;
channelSftp.connect(1000);
return channelSftp;
}
private static void getFileFromSftp(ChannelSftp channelSftp, String filename, String outFile) throws SftpException, IOException {
Path p = Paths.get(outFile != null ? outFile : "output");
try {
Files.copy(channelSftp.get(filename), p, REPLACE_EXISTING);
log.debug("File '" + filename + "' is written");
System.exit(0);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}