Java 如何使用apache SSHD ScpClient上载/下载文件

Java 如何使用apache SSHD ScpClient上载/下载文件,java,scp,sshd,apache-sshd,Java,Scp,Sshd,Apache Sshd,我不知道我在设置SCPC客户端以发送/接收文件时做错了什么 我正在使用ApacheMina SSHD库启动一个SSH服务器并尝试向它复制文件 以下是我的设置: SSHServer.java public class SSHServer { private SshServer sshServer; private static final Logger logger = LoggerFactory.getLogger(SSHServer.class); public S

我不知道我在设置SCPC客户端以发送/接收文件时做错了什么

我正在使用ApacheMina SSHD库启动一个SSH服务器并尝试向它复制文件

以下是我的设置:

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(由于未复制任何内容,因此失败):

以下是未注释上传行的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$1(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)
它似乎无法读取输入流,但我不知道我做错了什么,顺便说一句,这是一台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类构造的,我该怎么办?

我找到了答案

用下面的行替换上传和下载行

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向sshServer进行复制/从sshServer进行复制,并记录服务器端正在执行的命令,因为我发现没有必要包含远程,这是完全错误的


希望此设置有帮助。

对您有用吗?对我来说,没有什么能像这样工作。我没有得到任何错误,但文件没有被上传。是的,这对我来说是可行的。如果需要,我将为服务器和客户端添加完整的工作代码。是的,请添加工作代码。它不显示任何错误,但也不传输文件。另外,下面的代码对我也不起作用:``sshClient.setFileSystemFactory(新的VirtualFileSystemFactory(){@Override//显示不可能覆盖公共路径getUserHomeDir(SessionContext会话)抛出IOException{return Paths.get(“C:/Users/u660221”);};```另外,有必要在服务器设置中添加这一行:“sshServer.setCommandFactory(新的ScpCommandFactory());”我希望您已经根据您的系统修改了文件路径,问题中提到的代码对我适用。您需要根据您的系统使用文件路径。若要查看错误,您需要在记录器中为sshd lib启用调试模式,但有一些错误是您无法看到的。谢谢,经过一些调整后,它可以正常工作:)
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);