【问题标题】:C++ popen pipe doesn't close correctly with pclose for "ps aux" commandC++ popen 管道没有正确关闭“ps aux”命令的 pclose
【发布时间】:2018-07-31 04:32:07
【问题描述】:

我正在运行 MacOS,并希望执行“ps aux”命令并通过我的应用程序获取其输出。我写了一个使用 popen 函数执行命令的方法:

std::string exec(const char* cmd) {

    char buffer[128];
    std::string result = "";

    FILE* pipe = popen(cmd, "r");
    if (!pipe) throw std::runtime_error("popen() failed!2");
    try {
        while (!feof(pipe)) {
            if (fgets(buffer, 128, pipe) != NULL)
                result += buffer;
        }
    } catch (...) {
        pclose(pipe);

        throw;
    }
    pclose(pipe);


    return result;
}

我有一个不断运行 exec("ps aux") 函数的循环。问题是来自 popen 的管道没有关闭,我已经使用终端中的“lsof”命令进行了检查。大约 20 秒后,应用程序打开了大约 300 个文件描述符,这会阻止应用程序从循环中打开更多管道(运行“ps aux”命令)。

我发现,exec 函数适用于其他命令(管道正确关闭),例如“netstat”,因此它必须是“ps aux”命令中阻止管道关闭的东西.

我已经对这个问题进行了很多搜索,但没有找到任何解决方案。 有人可以指出我正确的方向吗?

谢谢!

【问题讨论】:

标签: c++ popen pclose


【解决方案1】:

我看不出您的代码有什么特别的问题。对于这些事情,我使用带有std::unique_ptr 的自定义删除器来确保文件在所有可能的出口处都关闭。

还请注意,出于某些原因,不建议使用while(eof(...)) 进行循环。一种是在发生错误时未设置 eof。 More info here.

// RAII piped FILE*

// custom deleter for unique_ptr
struct piped_file_closer
{
    void operator()(std::FILE* fp) const { pclose(fp); }
};

// custom unique_ptr for piped FILE*
using unique_PIPE_handle = std::unique_ptr<std::FILE, piped_file_closer>;

//
unique_PIPE_handle open_piped_command(std::string const& cmd, char const* mode)
{
    auto p = popen(cmd.c_str(), mode);

    if(!p)
        throw std::runtime_error(std::strerror(errno));

    return unique_PIPE_handle{p};
}

// exception safe piped reading
std::string piped_read(std::string const& cmd)
{
    std::string output;

    if(auto pipe = open_piped_command(cmd, "r"))
    {
        char buf[512];
        while(auto len = std::fread(buf, sizeof(char), sizeof(buf), pipe.get()))
            output.append(buf, len);

        if(std::ferror(pipe.get()))
            throw std::runtime_error("error reading from pipe");
    }

    return output;
}

在我的系统上调用 auto output = piped_read("ps aux"); 数百次不会产生您使用此代码的错误。

【讨论】:

  • 感谢您的帮助!但是,使用该代码我仍然遇到这个问题 - 应用程序崩溃并显示该消息:“应用程序特定信息:abort() 调用终止,类型为 std::runtime_error:Too many open files”
  • 运行数百次不会导致应用程序崩溃,但运行 300 次肯定会因为如果我没记错的话,MacOS 上每个进程打开的文件描述符的默认限制是 256。跨度>
  • @MrWhite 每次调用后,该调用的文件描述符都应该关闭,这样您就可以根据需要多次运行该命令。我的猜测是您的问题在其他地方?也许是一些微妙的未定义行为?我现在正在认真地对这段代码进行压力测试,并且文件描述符计数在不断循环您的命令时没有改变。
  • @MrWhite 现在我正在对 您的 代码进行压力测试并得到相同的结果,我的机器上没有问题。也许您发布的代码很好,而问题是别的?
  • 很抱歉,如果“ps aux”命令成功执行,我没有关闭在循环中打开的套接字,这就是导致文件描述符数量增加的原因:/
猜你喜欢
  • 1970-01-01
  • 2022-10-21
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 2011-10-27
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
相关资源
最近更新 更多