【问题标题】:C++ app hangs on exit when I envoke a script and leave the script running当我调用脚本并让脚本运行时,C++ 应用程序在退出时挂起
【发布时间】:2014-04-03 17:43:06
【问题描述】:

我有一个在 Ubuntu 10.04 上运行的 C++/Qt 程序。我正在使用带有 RSA 密钥的 x-windows (ssh -X) 运行远程应用程序,以防止密码对话框。 C++/Qt 程序允许用户调用 shell 脚本。 C++/Qt 程序必须以“gksudo -k”运行。

我遇到的问题是,当我从我的程序调用 shell 脚本时,如果我让远程应用程序运行,它会导致本地 C++/Qt 程序中的一个线程在退出时挂起。 (我希望能够让 ssh 会话保持运行,而不影响重新启动 C++/Qt 程序)

来自 C++ 代码:

try
{
    system(script.c_str());
}
catch (exception& e)
{
    throw;
}
catch ( ... )
{
    ThrowException("Controller::LaunchScript()");
}

shell 脚本位于 /usr/local/bin,如下所示:

#!/bin/sh
ip_address='192.168.0.1'
remote_usr='xxusrxx'
remote_cmd='/usr/local/bin/remote_application'

cmd="ssh -X "$remote_usr"@"$ip_address" \""$remote_cmd"\""
eval $cmd &

有什么想法或建议吗?

更新 1:

当我查看使用“ps -ef”运行的进程时,会显示 C++/Qt 程序和启动器脚本,但会显示“ssh -X”。当我重新启动我的 C++/Qt 程序时,它会抛出一个错误“地址已在使用中”,就像我过去尝试启动应用程序而另一个实例已经在运行时一样。

更新 2:

我可能会在兔子洞里走得更远,但我现在正在研究 sudo+xauth 问题和解决方案。当前失败的尝试正在添加:

export XAUTHORITY=/home/xxusrxx/.Xauthority
sudo -E -u xxusrxx

此外,挂起的 C++/Qt 进程似乎已失效。一种可能性是在启动时跟踪应用程序“清理”失效的进程。

【问题讨论】:

  • 在后台运行 $cmd 是有道理的,但它可能会导致您的问题。试试这个作为快速测试,将 ssh args 修改为 ssh -t -t -X ...。这适用于 shell 脚本中的这个问题(没有 C++ 包装程序)。祝你好运。
  • @shellter - 我尝试删除“&”并添加“-t -t”,但行为没有任何变化。
  • 如果我的想法可行,那么& 应该没问题。它似乎不太可能起作用,但为了确定,将其放回并重新测试。对不起,ssh 让大家头疼。我不会在这个上提供太多其他东西。祝你好运。
  • 这个问题可能与某些守护程序/服务有关,这些守护程序/服务由 Qt 框架自动启动,但在您的应用程序启动时不会自动退出,并保持 X 通道打开。
  • @twalberg - 我该如何修复它或至少缩小哪个守护程序可能使其保持打开状态?

标签: c++ linux bash qt shell


【解决方案1】:

尝试将所有文​​件描述符(stdin、stdout、stderr)重定向到 /dev/null。

在您的 shell 脚本中,更改为:

eval $cmd >/dev/null 2>&1 &

其实我也不知道为什么要eval,直接调用ssh就好了:

ssh -X "$remote_usr"@"$ip_address" "$remote_cmd" >/dev/null 2>&1 &

>/dev/null - 这显然会重定向标准输出。
2>&1 - 这会将标准错误(fd 2)重定向到标准输出( fd 1) 我们之前重定向到 /dev/null,所以现在它们都被重定向到 /dev/null
& - 分叉到后台会自动将标准输入重定向到 /dev/null

同样,直接在 C++/Qt 中,您可以在 QStringList 的末尾添加另一个字符串,就像 Kuba Ober 向您展示的那样

<< remote_cmd << ">/dev/null 2>&1")

回复您的更新:

您在更新中说 “当我查看使用 'ps -ef' 运行的进程时,C++/Qt 程序和启动器脚本都会出现,但 'ssh -X' 会。"

这是否意味着您不再有卡住的线程/进程?

你还说“当我重新启动我的 C++/Qt 程序时,它会抛出一个错误“地址已在使用中””
我想是这样的,因为当您在前一个 ssh 客户端仍在运行(并转发 X11)时再次启动 ssh 时,它会再次在远程连接,并在那里告诉 sshd 服务器打开一个端口以侦听 X 服务器连接,并且然后它抱怨该端口(或 interface_address:port 组合)已在使用中。 如果您不需要多个 ssh 连接,简单的解决方案是在启动应用程序之前终止现有的 ssh 连接。否则,您必须研究如何强制 sshd 绑定到另一个端口或类似的东西。也许以其他用户身份登录会自动解决问题。

这里有一个重要提示:我真的没有太多关于 X11 转发的经验,所以我只是假设它是如何工作的,所以我在写这篇文章。我可能错了。

【讨论】:

  • 运行时出现错误:“$1: 模糊重定向。我通过将 $1 替换为 /dev/null 来运行它,但结果与我的脚本相同。它运行,但是当我重新启动我的 C++/Qt 程序,它不会启动。
  • 呃……我的错……这不是美元符号($),而是与号(&),我想我一定累了……$1实际上代表转发的第一个参数当它被调用时到你的脚本......我现在会修复我的答案。尝试一下,但是 2>/dev/null 也应该可以工作......所以也许这毕竟不是你问题的原因:-/
  • 现在我在你的问题中发现了更新,所以我也更新了我的答案:)
  • 我能够接受您的建议,并在 ssh 命令的开头添加了“sudo -E -u xxuserxx”,但我还发现有一个已失效的进程仍在徘徊.我现在使用 bash 脚本启动 C++/Qt 程序,该脚本在终止时会找到 C++/Qt 程序的 PID,并在退出时终止与其相关的所有已失效进程。
  • 这与您一开始的已失效进程相同吗?还是您现在的行为略有不同?我觉得我的回答对你帮助不大,但你还是接受了。这将极大地降低您的问题对 stackoverflow 上其他用户的可见性,这些用户可能会对您有所帮助。随意删除接受的标志!
【解决方案2】:

由于您使用 Qt,没有理由使用 system 调用,也没有理由使用帮助脚本。最后,将 system 调用包装在 try-catch 块中是没有意义的,因为它不会引发异常。它是一个返回结果的 C 函数。

你可以使用QProcess::startDetached,你的代码不会等待任何东西:

QString ip_address="192.168.0.1"
QString remote_usr="xxusrxx"
QString remote_cmd="/usr/local/bin/remote_application"

if (!QProcess::startDetached("ssh", QStringList()
  << "-X" << QString("%1@%2").arg(remote_usr).arg(ip_address)
  << remote_cmd)
  ThrowException("Controller::LaunchScript()");

你可以类似地启动脚本,但脚本真的没有意义。

【讨论】:

  • 这是我最初尝试做的,但得到了相同的结果。我不知道它是否与我们运行 C++/Qt 程序时使用的“gksudo -k”有关,还是与“ssh -X”有关。无论如何,这似乎仍然在退出时锁定了某些东西。
  • @Axe "我不知道它是否与我们运行 C++/Qt 程序时使用的 'gksudo -k' 或只是 'ssh -X' 有关系" 好吧,试试看首先没有gksudo,看看这是否会改变事情。只有你能回答那个问题。
猜你喜欢
  • 2018-12-13
  • 2023-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-28
  • 1970-01-01
  • 2011-11-18
  • 2021-06-08
相关资源
最近更新 更多