【问题标题】:Why doesnt jsch execute the scp command?为什么jsch不执行scp命令?
【发布时间】:2020-09-06 15:56:55
【问题描述】:

我正在尝试使用scp 将文件从本地传输到远程。本地是 windows(OpenSSH 作为服务运行),远程是 FreeBSD(已设置 rsa 密钥)。 为此,我正在使用 Jsch 库。

try {
        if (ses == null) ses = fsaTo.getSession();
        channel = ses.openChannel("exec");
        String cmd = "scp "+ UserHostIdentity.getTransferUser(fsaFrom.getSystem()) + "@" 
                + UserHostIdentity.getTransferHost(fsaFrom.getSystem()) + ":"
                + from + " " 
                + to;
        ((ChannelExec)channel).setCommand(cmd);
        ((ChannelExec)channel).setErrStream(System.err);
        channel.connect();
    } catch (JSchException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

命令cmd 我手动执行它测试它并且它工作。这就是我启动会话的方式:

JSch jsch = new JSch();
    try {
        sshSession = jsch.getSession(UserHostIdentity.getTransferUser(fs), UserHostIdentity.getTransferHost(fs),22);
        UserInfo lui = UserHostIdentity.getTransferUserInfo(fs);
        sshSession.setUserInfo(lui);
        sshSession.setConfig("StrictHostKeyChecking", "no");
        sshSession.connect();
    } catch (JSchException e) {
        logger.error("Could not access fileserver.");
        throw new RuntimeException(e);
    }

问题是在调用channel.connect() 之后没有任何反应,没有错误,什么都没有。 在相同的上下文中,以下代码执行"sha256 -q " + filePath 并返回正确的结果:

public String doCommand(String cmd) {
    if (sshSession == null) {
        initiateConnection();
    }

    Channel channel;
    String result = "";
    try {
        channel = sshSession.openChannel("exec");
        ((ChannelExec)channel).setCommand(cmd);
        channel.setInputStream(null);
        ((ChannelExec)channel).setErrStream(System.err);

        InputStream input = channel.getInputStream();
        channel.connect(); 
        InputStreamReader inputReader = new InputStreamReader(input);
        BufferedReader bufferedReader = new BufferedReader(inputReader);
        String line = null;

        while((line = bufferedReader.readLine()) != null){
            result = line;
        }
        bufferedReader.close();
        inputReader.close();
        channel.disconnect();
    } catch (JSchException e) {
        logger.error("Problem with communication to Fileserver.");
        throw new RuntimeException(e);
    } catch (IOException e) {
        logger.error("Problem with command stream.");
        throw new RuntimeException(e);
    }
    return result;
}

我的问题是,为什么它不能与 scp 命令一起使用。

【问题讨论】:

    标签: java scp jsch


    【解决方案1】:

    如果您已经在使用 JSch 库,为什么不使用 SFTP?

    查看使用JSch SFTP上传文件的示例代码:

    public void uploadFile(File file, String location) {
        ChannelSftp channelSftp = null;
        try {
            channelSftp = (ChannelSftp)connect();
            if(location.startsWith(ROOT_DIR)) {
                channelSftp.cd(ROOT_DIR);
            }
            final List<String> directories = Splitter.on(File.separatorChar).omitEmptyStrings().splitToList(location);
            for(String dir : directories) {
                try {
                    channelSftp.ls(dir);
                } catch (SftpException e) {
                    channelSftp.mkdir(dir);
                }
                channelSftp.cd(dir);
            }
            if(LOGGER.isDebugEnabled()) {
                LOGGER.debug("Uploading file " + file.getPath() + " in " + location);
            }
            channelSftp.put(new FileInputStream(file), file.getName());
        } catch(Throwable e) {
            throw new RuntimeException("Upload file " + file.getPath() + " failed.", e);
        } finally {
            disconnect(channelSftp);
        }
    }
    

    【讨论】:

      【解决方案2】:

      好的,所以你的代码正在做的是:

      1. 使用 SSH 连接到&lt;fsaTo&gt;
      2. &lt;fsaTo&gt; 上运行命令“scp @:/”。

      scp 命令将尝试打开另一个 SSH 连接 back&lt;fsaFrom&gt; ... 这可能是这个主机 ... 并且 pull 文件回到那个连接

      这可能有效,但仅在以下情况下有效:

      • &lt;fsaFrom&gt; 正在监听传入的 SSH 连接
      • 您使用的 &lt;fsaTo&gt; 帐户有一个 SSH 私钥(不带密码),该私钥对应于注册为以 &lt;user&gt; 登录 &lt;fsaFrom&gt; 的公钥之一。

      有一种更好的方法,它没有任何先决条件。当您将scp 命令作为普通命令运行时,在远程系统上使用了一些未记录的scp 命令命令行开关。

      • scp -f &lt;remote-file&gt;&lt;remote-file&gt; 读取数据并将其发送到 ssh 输出流。
      • scp -t &lt;remote-file&gt; 从 ssh 输入流中读取并输出到 &lt;remote-file&gt;

      更多详情请见SSH: The Secure Shell, the definitive guide section 3.8

      或者,如果您只是想要一个示例,JSch ScpTo.java example 会显示如何做您正在尝试做的事情。

      【讨论】:

      • 当满足这些条件时它仍然不起作用,但仍然无法解释
      【解决方案3】:

      最好的开始可能是使用详细参数运行 scp:

      scp -v src dest

      或者如果这没有帮助,请查看您是否可以安装 strace(如果您还没有安装)并运行:

      strace scp -v src dest

      这应该会提示您可能出现的问题(尽管您说您设置了主机密钥,但您是否对其进行了测试?),例如:

      • 主机密钥验证可能失败
      • 您可能需要输入私钥的密码
      • 可能存在一些安全不兼容问题

      另外你忘记继续阅读 InputStream,也许在 channel.connect() 行周围做这样的事情:

      InputStream in = channel.getInputStream();
      channel.connect();
      in.transferTo(System.out);
      

      或者像使用 sha256 命令一样继续读取 InputStream(来自 scp 的标准输出),直到进程完成(这样它就可以在我的机器上运行)。

      【讨论】:

      • 您能否描述一下您所说的“它在不阻塞的情况下交叉读取两个通道的读取,另一种方法是使用单独的线程,每个线程都可以阻塞,直到有东西要读取。”我也尝试根据您链接的帖子输出输出,但代码只是挂起。 inerr 什么都不返回,并且通道仍然打开。顺便说一句,我正在尝试移动一个空的 .txt 文件。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-26
      • 2022-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多