无法使用jcraft JSch连接到SFTP
我想通过使用jcraft版本0.1.52的ssh跳转主机代理连接到SFTP位置。但得到“连接关闭外国主机”在我的代码异常。我花了好足够的时间在看文档,但无法弄清楚的问题是什么无法使用jcraft JSch连接到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();
}
}
}
真的很感激,如果有人可以帮助。谢谢!
这里的方法对我来说工作得很好。
基本上它是一个隧道到 您的sftp主机。它通过jumphost或隧道主机创建一个到你的sftp主机的隧道,并通过sftpChannel从这个隧道“本地主机”端口(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);
}
}
}
谢谢谢尔盖。我可以看到你删除了跳转主机代理配置。更新后的代码不适用于我的用例,因为sftp连接是通过跳转主机。 – Techji
如果您想要创建一个与原始代码有点不同的隧道。稍后我会更新代码。 –
@Techji我已经更新了答案。你可以通过隧道实现,就像我之前说过的那样。它工作正常。 –
通知connect()方法,而不是'调用Runtime.getRuntime()EXEC(命令);'它应该是'调用Runtime.getRuntime()EXEC(CMD);'太 –
塞吉本纳2,那是我现在编辑的帖子中的一个错字。虽然很漂亮! – Techji