如何使用 apache SSHD ScpClient upload/download 文件
How to upload/download files using apache SSHD ScpClient
我不知道我在为 send/receive 文件设置 ScpClient 时做错了什么。
我正在使用 Apache MINA SSHD 库启动 SSH 服务器并尝试复制文件to/from。
这是我的设置:
SSHServer.java
public class SSHServer {
private SshServer sshServer;
private static final Logger logger = LoggerFactory.getLogger(SSHServer.class);
public SSHServer() {
sshServer = SshServer.setUpDefaultServer();
sshServer.setHost("127.0.0.1");
sshServer.setPort(22);
sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
//Accept all keys for authentication
//sshServer.setPublickeyAuthenticator((s, publicKey, serverSession) -> true);
sshServer.setFileSystemFactory(new VirtualFileSystemFactory() {
@Override
public Path getUserHomeDir(SessionContext session) throws IOException {
return Paths.get("C:/Users/u660221");
}
});
sshServer.setCommandFactory(new ScpCommandFactory());
sshServer.setPasswordAuthenticator((username, password, serverSession) -> {
logger.debug("authenticating: {} password: {}", username, password);
return username != null && "changeit".equals(password);
});
}
public int getPort() {
return sshServer.getPort();
}
public String getHost() {
return sshServer.getHost();
}
public void startServer() throws IOException{
sshServer.start();
logger.debug("SSHServer started...");
}
public void stopServer() throws IOException {
sshServer.stop();
logger.debug("SSHServer stopped...");
}
}
SSHClient.java
public class SSHClient {
private SshClient sshClient;
private String username;
private String host;
private String password;
private int port;
private static final Logger logger = LoggerFactory.getLogger(SSHClient.class);
private SSHClient(){}
public SSHClient(String username, String password, String host, int port) {
sshClient = SshClient.setUpDefaultClient();
sshClient.setFileSystemFactory(new VirtualFileSystemFactory() {
@Override
public Path getUserHomeDir(SessionContext session) throws IOException {
return Paths.get("C:/Users/u660221");
}
});
this.username = username;
this.password = password;
this.host = host;
this.port = port;
}
public ClientSession connect() throws IOException {
ConnectFuture connectFuture = sshClient.connect(username, host, port).verify();
logger.debug("SSHClient is connected: {}", connectFuture.isConnected());
return connectFuture.getSession();
}
public void startClient() {
sshClient.start();
logger.debug("SSHClient is started...");
}
public void stopClient() {
sshClient.stop();
logger.debug("SSHClient is stopped...");
}
}
TestSSH.java
public class TestSSH {
private static final Logger logger = LoggerFactory.getLogger(TestSSH.class);
public static void main(String[] args) throws IOException {
SSHServer sshServer = new SSHServer();
sshServer.startServer();
logger.debug("Started SSHServer on HOST: " + sshServer.getHost() + " PORT: " + sshServer.getPort());
SSHClient sshClient = new SSHClient("u660221", "changeit",
sshServer.getHost(), sshServer.getPort());
sshClient.startClient();
ClientSession clientSession = sshClient.connect();
clientSession.addPasswordIdentity("changeit");
AuthFuture authFuture = clientSession.auth().verify();
logger.debug("is client auth success: " + authFuture.isSuccess());
logger.debug("client connect address: {}", clientSession.getConnectAddress().toString());
ScpClientCreator creator = ScpClientCreator.instance();
ScpClient scpClient = creator.createScpClient(clientSession);
//FileOutputStream fo = new FileOutputStream("C:\Users\u660221\destination\file.jar");
//scpClient.download("u660221@127.0.0.1:\Project\file.jar", fo); //this works!!!!!
//does not work //scpClient.upload(Paths.get("C:/Users/u660221/source"), "u660221@127.0.0.1:/destination", ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes, ScpClient.Option.TargetIsDirectory);
scpClient.download("u660221@127.0.0.1:/source/", Paths.get("C:/Users/u660221/destination"), ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes); //does not work
}
}
这是未注释的下载行的 o/p(由于未复制任何内容,因此失败):
2020-07-02 13:57:15,186 DEBUG c.w.v.g.s.SSHServer [main] SSHServer started...
2020-07-02 13:57:15,202 DEBUG c.w.v.g.s.TestSSH [main] Started SSHServer on HOST: 127.0.0.1 PORT: 22
2020-07-02 13:57:15,357 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is started...
2020-07-02 13:57:15,896 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is connected: true
2020-07-02 13:57:17,690 DEBUG c.w.v.g.s.SSHServer [sshd-SshServer[25a6944c](port=22)-nio2-thread-1] authenticating: u660221 password: changeit
2020-07-02 13:57:17,695 DEBUG c.w.v.g.s.TestSSH [main] is client auth success: true
2020-07-02 13:57:17,696 DEBUG c.w.v.g.s.TestSSH [main] client connect address: /127.0.0.1:22
这是 o/p 未注释的上传行:
2020-07-02 14:14:08,034 DEBUG c.w.v.g.s.SSHServer [main] SSHServer started...
2020-07-02 14:14:08,044 DEBUG c.w.v.g.s.TestSSH [main] Started SSHServer on HOST: 127.0.0.1 PORT: 22
2020-07-02 14:14:08,175 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is started...
2020-07-02 14:14:08,598 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is connected: true
2020-07-02 14:14:10,412 DEBUG c.w.v.g.s.SSHServer [sshd-SshServer[77888435](port=22)-nio2-thread-3] authenticating: u660221 password: changeit
2020-07-02 14:14:10,417 DEBUG c.w.v.g.s.TestSSH [main] is client auth success: true
2020-07-02 14:14:10,417 DEBUG c.w.v.g.s.TestSSH [main] client connect address: /127.0.0.1:22
Exception in thread "main" java.io.EOFException: readAck - EOF before ACK
at org.apache.sshd.common.scp.ScpHelper.readAck(ScpHelper.java:849)
at org.apache.sshd.common.scp.ScpHelper.sendPaths(ScpHelper.java:456)
at org.apache.sshd.client.scp.AbstractScpClient.lambda$upload(AbstractScpClient.java:158)
at org.apache.sshd.client.scp.DefaultScpClient.runUpload(DefaultScpClient.java:145)
at org.apache.sshd.client.scp.AbstractScpClient.upload(AbstractScpClient.java:158)
at org.apache.sshd.client.scp.ScpClient.upload(ScpClient.java:119)
at org.apache.sshd.client.scp.ScpClient.upload(ScpClient.java:115)
at TestSSH.main(TestSSH.java:29)
它似乎无法从 InputStream 读取,但我不知道我做错了什么,顺便说一句,这是一台 windows 机器。为此,我需要在 windows 中安装 scp 吗?
启用调试日志记录后,可以看到这些日志:
2020-07-03 13:40:41,825 DEBUG o.a.s.s.s.ScpCommand [sshd-SshServer[776aec5c](port=22)-nio2-thread-1] Executing command scp -r -d -p -t -- u660221@127.0.0.1:/destination
2020-07-03 13:40:41,825 DEBUG o.a.s.s.s.ScpCommand [sshd-SshServer[776aec5c](port=22)-nio2-thread-1] Unknown flag ('-') in command=scp -r -d -p -t -- u660221@127.0.0.1:/destination
但是这是由 ScpClient 构建的 class 只有我应该做什么?
我找到了答案。
用下面的行替换上传和下载行
scpClient.upload(
Paths.get("C:\Users\u660221\source"),
"/destination",
ScpClient.Option.Recursive,
ScpClient.Option.PreserveAttributes,
ScpClient.Option.TargetIsDirectory );
scpClient.download(
"/source",
Paths.get("C:\Users\u660221\destination"),
ScpClient.Option.Recursive,
ScpClient.Option.PreserveAttributes,
ScpClient.Option.TargetIsDirectory );
方法中无需再次指定遥控器。
这是我发现使用 pscp 来复制 to/from sshServer 并记录在服务器端执行的命令,因为我发现没有必要包括远程,这是完全错误的。
我不知道我在为 send/receive 文件设置 ScpClient 时做错了什么。
我正在使用 Apache MINA SSHD 库启动 SSH 服务器并尝试复制文件to/from。
这是我的设置:
SSHServer.java
public class SSHServer {
private SshServer sshServer;
private static final Logger logger = LoggerFactory.getLogger(SSHServer.class);
public SSHServer() {
sshServer = SshServer.setUpDefaultServer();
sshServer.setHost("127.0.0.1");
sshServer.setPort(22);
sshServer.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
//Accept all keys for authentication
//sshServer.setPublickeyAuthenticator((s, publicKey, serverSession) -> true);
sshServer.setFileSystemFactory(new VirtualFileSystemFactory() {
@Override
public Path getUserHomeDir(SessionContext session) throws IOException {
return Paths.get("C:/Users/u660221");
}
});
sshServer.setCommandFactory(new ScpCommandFactory());
sshServer.setPasswordAuthenticator((username, password, serverSession) -> {
logger.debug("authenticating: {} password: {}", username, password);
return username != null && "changeit".equals(password);
});
}
public int getPort() {
return sshServer.getPort();
}
public String getHost() {
return sshServer.getHost();
}
public void startServer() throws IOException{
sshServer.start();
logger.debug("SSHServer started...");
}
public void stopServer() throws IOException {
sshServer.stop();
logger.debug("SSHServer stopped...");
}
}
SSHClient.java
public class SSHClient {
private SshClient sshClient;
private String username;
private String host;
private String password;
private int port;
private static final Logger logger = LoggerFactory.getLogger(SSHClient.class);
private SSHClient(){}
public SSHClient(String username, String password, String host, int port) {
sshClient = SshClient.setUpDefaultClient();
sshClient.setFileSystemFactory(new VirtualFileSystemFactory() {
@Override
public Path getUserHomeDir(SessionContext session) throws IOException {
return Paths.get("C:/Users/u660221");
}
});
this.username = username;
this.password = password;
this.host = host;
this.port = port;
}
public ClientSession connect() throws IOException {
ConnectFuture connectFuture = sshClient.connect(username, host, port).verify();
logger.debug("SSHClient is connected: {}", connectFuture.isConnected());
return connectFuture.getSession();
}
public void startClient() {
sshClient.start();
logger.debug("SSHClient is started...");
}
public void stopClient() {
sshClient.stop();
logger.debug("SSHClient is stopped...");
}
}
TestSSH.java
public class TestSSH {
private static final Logger logger = LoggerFactory.getLogger(TestSSH.class);
public static void main(String[] args) throws IOException {
SSHServer sshServer = new SSHServer();
sshServer.startServer();
logger.debug("Started SSHServer on HOST: " + sshServer.getHost() + " PORT: " + sshServer.getPort());
SSHClient sshClient = new SSHClient("u660221", "changeit",
sshServer.getHost(), sshServer.getPort());
sshClient.startClient();
ClientSession clientSession = sshClient.connect();
clientSession.addPasswordIdentity("changeit");
AuthFuture authFuture = clientSession.auth().verify();
logger.debug("is client auth success: " + authFuture.isSuccess());
logger.debug("client connect address: {}", clientSession.getConnectAddress().toString());
ScpClientCreator creator = ScpClientCreator.instance();
ScpClient scpClient = creator.createScpClient(clientSession);
//FileOutputStream fo = new FileOutputStream("C:\Users\u660221\destination\file.jar");
//scpClient.download("u660221@127.0.0.1:\Project\file.jar", fo); //this works!!!!!
//does not work //scpClient.upload(Paths.get("C:/Users/u660221/source"), "u660221@127.0.0.1:/destination", ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes, ScpClient.Option.TargetIsDirectory);
scpClient.download("u660221@127.0.0.1:/source/", Paths.get("C:/Users/u660221/destination"), ScpClient.Option.Recursive, ScpClient.Option.PreserveAttributes); //does not work
}
}
这是未注释的下载行的 o/p(由于未复制任何内容,因此失败):
2020-07-02 13:57:15,186 DEBUG c.w.v.g.s.SSHServer [main] SSHServer started...
2020-07-02 13:57:15,202 DEBUG c.w.v.g.s.TestSSH [main] Started SSHServer on HOST: 127.0.0.1 PORT: 22
2020-07-02 13:57:15,357 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is started...
2020-07-02 13:57:15,896 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is connected: true
2020-07-02 13:57:17,690 DEBUG c.w.v.g.s.SSHServer [sshd-SshServer[25a6944c](port=22)-nio2-thread-1] authenticating: u660221 password: changeit
2020-07-02 13:57:17,695 DEBUG c.w.v.g.s.TestSSH [main] is client auth success: true
2020-07-02 13:57:17,696 DEBUG c.w.v.g.s.TestSSH [main] client connect address: /127.0.0.1:22
这是 o/p 未注释的上传行:
2020-07-02 14:14:08,034 DEBUG c.w.v.g.s.SSHServer [main] SSHServer started...
2020-07-02 14:14:08,044 DEBUG c.w.v.g.s.TestSSH [main] Started SSHServer on HOST: 127.0.0.1 PORT: 22
2020-07-02 14:14:08,175 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is started...
2020-07-02 14:14:08,598 DEBUG c.w.v.g.s.SSHClient [main] SSHClient is connected: true
2020-07-02 14:14:10,412 DEBUG c.w.v.g.s.SSHServer [sshd-SshServer[77888435](port=22)-nio2-thread-3] authenticating: u660221 password: changeit
2020-07-02 14:14:10,417 DEBUG c.w.v.g.s.TestSSH [main] is client auth success: true
2020-07-02 14:14:10,417 DEBUG c.w.v.g.s.TestSSH [main] client connect address: /127.0.0.1:22
Exception in thread "main" java.io.EOFException: readAck - EOF before ACK
at org.apache.sshd.common.scp.ScpHelper.readAck(ScpHelper.java:849)
at org.apache.sshd.common.scp.ScpHelper.sendPaths(ScpHelper.java:456)
at org.apache.sshd.client.scp.AbstractScpClient.lambda$upload(AbstractScpClient.java:158)
at org.apache.sshd.client.scp.DefaultScpClient.runUpload(DefaultScpClient.java:145)
at org.apache.sshd.client.scp.AbstractScpClient.upload(AbstractScpClient.java:158)
at org.apache.sshd.client.scp.ScpClient.upload(ScpClient.java:119)
at org.apache.sshd.client.scp.ScpClient.upload(ScpClient.java:115)
at TestSSH.main(TestSSH.java:29)
它似乎无法从 InputStream 读取,但我不知道我做错了什么,顺便说一句,这是一台 windows 机器。为此,我需要在 windows 中安装 scp 吗?
启用调试日志记录后,可以看到这些日志:
2020-07-03 13:40:41,825 DEBUG o.a.s.s.s.ScpCommand [sshd-SshServer[776aec5c](port=22)-nio2-thread-1] Executing command scp -r -d -p -t -- u660221@127.0.0.1:/destination
2020-07-03 13:40:41,825 DEBUG o.a.s.s.s.ScpCommand [sshd-SshServer[776aec5c](port=22)-nio2-thread-1] Unknown flag ('-') in command=scp -r -d -p -t -- u660221@127.0.0.1:/destination
但是这是由 ScpClient 构建的 class 只有我应该做什么?
我找到了答案。
用下面的行替换上传和下载行
scpClient.upload(
Paths.get("C:\Users\u660221\source"),
"/destination",
ScpClient.Option.Recursive,
ScpClient.Option.PreserveAttributes,
ScpClient.Option.TargetIsDirectory );
scpClient.download(
"/source",
Paths.get("C:\Users\u660221\destination"),
ScpClient.Option.Recursive,
ScpClient.Option.PreserveAttributes,
ScpClient.Option.TargetIsDirectory );
方法中无需再次指定遥控器。
这是我发现使用 pscp 来复制 to/from sshServer 并记录在服务器端执行的命令,因为我发现没有必要包括远程,这是完全错误的。