【问题标题】:Problem with calling rsync+ssh from java on windows在 windows 上从 java 调用 rsync+ssh 的问题
【发布时间】:2010-10-15 18:16:23
【问题描述】:

我在安装了 cygwin 的 windows vista 上从 java 调用 rsync 时遇到问题。 将完全相同的命令粘贴到命令外壳中工作正常,这很奇怪。

我的测试 java 调用如下所示。

String[] envVars = {"PATH=c:/cygwin/bin;%PATH%"};
File workingDir = new File("c:/cygwin/bin/");
Process p = Runtime.getRuntime().exec("c:/cygwin/bin/rsync.exe -verbose -r -t -v --progress -e ssh /cygdrive/c/Users/dokeeffe/workspace/jrsync/ www.servername.net:/home/dokeeffe/rsync/",envVars,workingDir);

然后我启动 2 个流读取器线程来捕获并记录 Process p 的 inputStream 和 errorStream。

这是输出......

DEBUG: com.mddc.client.rsync.StreamGobbler - opening connection using: ssh www.servername.net rsync --server -vvtre.iLs . /home/dokeeffe/rsync/
DEBUG: com.mddc.client.rsync.StreamGobbler - rsync: pipe: Operation not permitted (1)
DEBUG: com.mddc.client.rsync.StreamGobbler - rsync error: error in IPC code (code 14) at /home/lapo/packaging/rsync-3.0.4-1/src/rsync-3.0.4/pipe.c(57) [sender=3.0.4]

发生错误的rsync代码是pipe.c(57),就是这个。

if (fd_pair(to_child_pipe) < 0 || fd_pair(from_child_pipe) < 0) {
    rsyserr(FERROR, errno, "pipe");
    exit_cleanup(RERR_IPC);
}

所以,由于某种原因,fd_pair(to_child_pipe)

如果有人有任何建议,那就太好了,因为我现在被困住了。 谢谢,

【问题讨论】:

    标签: java ssh rsync


    【解决方案1】:

    您是否在某处忘记了 ssh 私有/公共密钥库?

    【讨论】:

    • 是的,我已经设置了密钥库,当我进入 cmd 窗口或 cygwin shell 时,该命令工作正常(不需要密码)
    【解决方案2】:

    我从未尝试过使用不同的线程进行读/写,仅使用执行命令的同一线程。这会导致您的问题吗?

    您也可以尝试将 -v 传递给 ssh 以获取调试输出。这在过去帮助我解决了 ssh 连接问题。你会通过-e "ssh -v"

    【讨论】:

      【解决方案3】:

      cygwin 的 rsync 二进制分发版能识别 ssh 命令吗?当您放入 shell 时,您尝试执行的命令可能工作正常,因为 bash 之类的东西知道如何解释 ssh 命令以建立连接,即使用 ssh 程序为 rsync 程序创建连接。从您的调试信息中,我认为 rsync 正在等待连接,但收到了一个无法通过管道传输的字符串“ssh ...”。

      要解决这个问题,您必须让 bash 为您完成工作。在线程部分中查看this page 来照顾孩子。您需要派生一个命令外壳的实例并将您的命令写入外壳子进程。所以是这样的:

      Process p = Runtime.getRuntime().exec("c:/cygwin/bin/bash.exe");
      OutputStreamWriter osw = new OutputStreamWriter(p.getOutputStream());
      BufferedWriter bw = new BufferedWriter( osw, 100);
      try{
          bw.write(command);
          bw.close();
      }catch(IOExeception e){
          System.out.println("Problem writing command.");
      }
      

      您可能还想读取进程输出,因为如果您不读取它,它将停止执行。提供的链接很好地涵盖了该主题。

      【讨论】:

      • 我很高兴这有帮助。我在尝试执行“program
      【解决方案4】:

      谢谢大家,尤其是丹尼尔。你发给我的链接很棒。 最后我使用了 ProcessBuilder 而不是 Runtime.exec。 如果对任何人有帮助,这里是代码.....

                  ProcessBuilder pb = new ProcessBuilder(new String[]{"c:/cygwin/bin/rsync.exe"
                                                                      ,"-verbose",
                                                                      "-r",
                                                                      "-t",
                                                                      "-v",
                                                                      "--progress",
                                                                      "-e",
                                                                      "ssh",
                                                                      "/cygdrive/c/Users/dokeeffe/workspace/jrsync/",
                                                                      "www.servername.net:/home/dokeeffe/rsync/"});
              Map<String, String> env = pb.environment();
              env.put("PATH","/cygwin/bin;%PATH%");
              pb.directory(new File("c:/cygwin/bin/"));
              Process p = pb.start();
              StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(),"OUTPUT");
              StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(),"ERROR");
              outputGobbler.start();
              errorGobbler.start();
              int val = p.waitFor();
              if(val!=0){
                  throw new Exception("Rsync return code="+val);
              }
      

      【讨论】:

        【解决方案5】:

        我对类似问题的体验:

        我的常数:

        1. 构建系统是 ANT,在 Hudson 中运行

        2. 构建服务器是 Windows Server

        3. 远程测试服务器是Linux

        4. 不允许仅使用 rsync 守护进程 rsync over ssh

        我们做了什么

        1. 将 DeltaCopy 安装到 windows 服务器

        2. 按照这些说明设置 DeltaCopy,使其可以与 SSH 一起使用

        3. 我构建了以下 ANT 宏,并在 hudson 中运行它。 起初,我一直挂在这上面,没有任何反应。

          添加-vvv 而不是-v 会有所不同。这导致更多信息被添加到 hudson 日志中。

          <macrodef name="rsync">
          <attribute name="username"/>
          <attribute name="remoteServer"/>
          <attribute name="remoteDir"/>
          <attribute name="sourceDir"/> <!-- relative to basedir start and end with / (e.g. "/html/resources/" -->
          <sequential>
              <echo message="Starting rsync @{sourceDir} to @{remoteDir} on server @{remoteServer} as user @{username} at ${release.start}"/>
          
              <pathconvert property="cygwinbasepath" dirsep="/" pathsep="" description="Replace ':' '\' with '/' and assign value to property">
                  <path path="${basedir}" description="Original version" />
                  <!--Pathconvert will try to add the root directory to the "path", replace with empty string --> 
                  <filtermapper> 
                      <replacestring from=":" to="" />  
                  </filtermapper>
              </pathconvert>
              <echo message="${basedir} converted to ${cygwinbasepath}"/>
          
              <property name="rsync.cygwinSourcePath" value="/cygdrive/${cygwinbasepath}@{sourceDir}" />
              <!-- ${rsync.user}@${rsync.server}:${rsync.dir} -->
              <property name="rsync.remoteDestinationPath" value="@{remoteServer}:@{remoteDir}" />
          
              <echo message="trying to run:" />
              <!-- &quot; is escaped quote -->
              <echo>cmd /C rsync -avz -e &quot;ssh -v -l ${deployment.rsync.username} -i /cygdrive/C/cygwin/home/service-tomcat/.ssh/id_rsa&quot; --recursive --chmod=a=rw,Da+x ${rsync.cygwinSourcePath} ${rsync.remoteDestinationPath}</echo>
              <echo>
              </echo>
              <!-- 10 minute timeout -->
              <exec executable="C:\cygwin\bin\mintty.exe"
                  timeout="300000"
              >
                  <arg value="rsync"/>
                    <arg value="-avvvz"/>
                    <arg value="-e" />
                    <arg value="ssh -v -l ${deployment.rsync.username} -i /cygdrive/C/cygwin/home/vj-service-tomcat/.ssh/id_rsa" />
                    <arg value="--recursive"/>
                    <arg value="--chmod=a=rw,Da+x"/> 
                    <arg value="${rsync.cygwinSourcePath}"/>
                    <arg value="${rsync.remoteDestinationPath}"/>
              </exec>
          
              <echo>
              </echo>
          
          </sequential>
          

          让它工作的关键是执行C:\cygwin\bin\mintty.exe而不是cmd

        4. 然后,我在 Windows 服务器上手动运行 rsync 命令,其 known_hosts 文件已使用远程主机进行更新。 这必须以 hudson 用户的身份完成。我们在 windows 中使用 runas 命令以 hudson 用户身份启动 cygwin 控制台。

        【讨论】:

          【解决方案6】:

          我最近实现了类似的东西,并认为我会分享我的经验,因为调试问题需要相当长的时间。此问题是 google 上出现此问题的唯一实例之一。

          我的应用程序作为服务启动。运行 whoami 命令时,结果是“nt authority\system”。在 /home/myusername/.ssh 下设置了我的 SSH 密钥后,rsync 命令失败,因为 /home/SYSTEM/.ssh 下没有设置任何配置。

          将我的 /home/myusername/.ssh 目录复制到 /home/SYSTEM/.ssh 并使用以下字符串数组可以满足我的目的。将 PORT 替换为您的 ssh 端口。

          new String[]{"rsync", "-z", "-I", "-e", "ssh -p PORT", server + ":" + serverPath, clientPath}
          

          如果这是您的问题,请参阅链接here,了解有关在系统权限下启动 cmd.exe 以进行测试的详细信息。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-09-13
            • 2022-07-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-01-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多