【问题标题】:Start a remote process using java使用java启动远程进程
【发布时间】:2018-08-16 10:30:14
【问题描述】:

机器 A 使用 sshpass 连接到远程机器 B,而远程机器 B 没有直接让 ssh 访问 root,所以我通过 user 连接到它并使用 sudo,我也当他执行sudo su 时,已禁用user 的密码。当命令像ls -lrt /some/dir 这样简单时,我会得到正确的命令输出,但是当我在远程机器上启动服务器/shell 脚本时(服务器不需要时间,而脚本需要 1 分钟运行),输出会显示,但 bash 不会'不要恢复正常(即看起来它正在做一些工作,但我知道服务器已经启动/脚本已经完成)。

使用的命令:

sshpass -p 'password' ssh -o StrictHostKeyChecking=no user@192.168.0.3 "sudo ls /dev/ttyUSB*"

以上工作正常,我得到了输出并返回了 bash,这样我就可以编写更多命令并做一些事情了。

sshpass -p 'password' ssh -o StrictHostKeyChecking=no user@192.168.0.3 "sudo /root/path/server &"

sshpass -p 'password' ssh -o StrictHostKeyChecking=no user@192.168.0.3 "sudo /root/path/to/script/scriptTakes1Minute param1 param2"

但是,上述操作并没有按预期工作。看起来它正在工作,但不是没有返回 bash,所以我无法进一步编写命令。

我不能共享脚本或服务器程序,因为它是公司的代码。但服务器代码使用 UNIX 数据报套接字进行通信。

/* Creating a UNIX datagram socket for Server Application */
        if ((sock = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
        {
                perror("server: socket");
                exit(1);
        }

编辑 1:

当我尝试时

sshpass -p 'password' ssh -o StrictHostKeyChecking=no user@192.168.0.3 "sudo /root/path/server >/dev/null &2>1 </dev/null &"

服务器程序正确启动,但脚本没有按预期工作,也没有返回 bash,但是当我按下 ENTER 时,bash 返回,我知道这意味着什么,但不知道是什么。

编辑 2:

我无法将输出重定向到文件,因为我不知道该命令总共需要多少时间才能运行,可能需要一分钟或几分钟。

编辑 3:

我发现了一些很有帮助的东西(我猜)。保留在该机器 B 上的脚本在后台创建了几个进程,因此 sshpass 不会返回,直到所有这些后台进程从机器 B 手动终止。一旦这些程序被终止,我们就会得到该输出以及猛击回来。

编辑 4:

脚本创建 8 个在后台运行的 ppp 会话。

【问题讨论】:

  • 尝试致电process.getOutputStream().close() 看看是否有效果。
  • 我不知道需要多长时间,所以我无法关闭输出流,但 sshpass 命令在这里出错,而不是 java。请帮我解决这个问题或其他方法。
  • 关闭输出流不会停止进程。该进程获得 EOF。
  • 那么我应该什么时候关闭输出流? @KDM
  • 你可以把它放在 exec() 调用之后。由于 Control+C 似乎使您的应用程序工作 - 看起来应用程序正在等待一些输入。发送 EOF 可能会解决问题。

标签: linux bash shell ppp sshpass


【解决方案1】:

所以我使用 express 创建了一个简单的服务器

express = require('express');

app = express();

app.all('/', (req, res) => {
   res.send('anc\n');
})

app.listen(9099, () => {
   console.log('server started');
});

然后使用执行

sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@192.168.33.100 "node /tmp/server/index.js 1>/tmp/log 2>&1"

它将输出记录到/tmp/log。您可以在下面的屏幕截图中看到执行情况

如您所见,我也可以捕获日志。如果您有要运行的命令列表,那么我将使用 shell 脚本,而该脚本可以将单个脚本记录到它们各自的文件中或在主标准输出上吐出输出,并在我们在命令中使用的/tmp/log 中捕获

使用 sudo

如下图所示,它甚至可以与 sudo 一起使用。但是请注意,您不应该使用sudo su,因为这需要用户shell,并且您希望在传递给SSH的命令中使用sudo -u &lt;user&gt;

编辑:18 年 3 月 19 日

根据您的编辑,您提供了一个脚本

echo "First Line" 
ping 10.100.208.102 >/dev/null & 
echo "Last Line"

现在我假设您也想要输出Last Line,然后您也不想挂起终端。下面的测试命令对我有用

$ sshpass -p 'vagrant' ssh -o StrictHostKeyChecking=no vagrant@192.168.33.100 "sudo sh /tmp/server/ping.sh 1>/tmp/log 2>&1 && cat /tmp/log"
First Line
Last Line

$

【讨论】:

  • 我需要启动一个保存在/root/some/path 的脚本或服务器,所以我需要一个sudo,并且当我们执行sudo su 时我已经删除了密码。我可以使用redirection 将命令输出输出到一个文件中,但我希望能够以这种方式工作,因为我不知道为什么我正在尝试的东西不起作用。
  • 回复你使用的实际命令,我会告诉你如何使用它。我在测试时使用了无密码的 sudo,它运行良好
  • 请加入这个chat
  • 我在 EDIT 3 中用一个非常重要的细节编辑了这个问题。
【解决方案2】:

如果您希望 ssh 执行命令并在命令完成之前返回,请使用 -f 选项,例如 ssh -f user@host myServer。如果它可能产生输出,您可能需要重定向 stdout 和/或 stderr。

详见手册页:https://man.openbsd.org/ssh#f

【讨论】:

  • 我需要在java 程序中捕获输出。首先输出文件中的每个命令然后读取文件并删除它是最佳实践吗?这些程序有很多我必须像这样执行的 shell 命令。
  • 是的,您可以重定向到文件并用 Java 读取它们。或者您可以使用 ProcessBuilder。它允许您启动外部程序并将其输出作为 Java InputStreams 进行读取(在这种情况下,您不会将 -f 与 ssh 一起使用)。
  • 我在 EDIT 3 中用一个非常重要的细节编辑了这个问题。
  • 从您发布的内容来看,在我看来 ProcessBuilder 就是您想要的。有关如何从 Java 运行程序并收集其输出的示例,请参阅:stackoverflow.com/questions/16714127/…
【解决方案3】:

只需再使用一行代码process.waitFor(); 即可解决您的问题:-

 process = Runtime.getRuntime().exec(SHELL_COMMAND);
 process.waitFor();// add this line to complete execution of your shell command
 System.out.println("LLLLLLLOOOOOOOOOKKKKKKKK started process");

【讨论】:

  • IllegalMonitorStateException 发生,我正在尝试解决它,只是让您知道。
  • @ShashankSingh,我用不同的方法修改了我的答案。试试这个,让我知道。
  • 问题仍然存在。谢谢你的尝试。再观察一下,当我按下CTRL+C 时,可以看到输出,这是预期的正确输出。不知道是sshpass问题还是java问题。
  • 只需尝试从 java 执行 ls 命令并检查是否是 java 问题或任何其他问题。还要验证权限。
  • 也注释掉 //process.destroy();并检查。
猜你喜欢
  • 2018-05-09
  • 2014-12-04
  • 1970-01-01
  • 1970-01-01
  • 2014-06-03
  • 1970-01-01
  • 2011-01-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多