我正在运行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& #34;命令阻止管道关闭。
我已经搜索过很多关于这个问题的信息,但是没有找到任何解决方案。 有人可以指出我正确的方向吗?
谢谢!
答案 0 :(得分:0)
我无法查看代码的具体错误。对于这些内容,我使用带有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");
数百次不会产生您的错误。