Я использую 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» должно быть что-то, что препятствует закрытию канала.
Я много искал об этой проблеме, но не нашел никакого решения.
Может кто-нибудь, пожалуйста, укажите мне в правильном направлении?
Спасибо!
Я не вижу, что конкретно не так с вашим кодом. Для этих вещей я использую пользовательское средство удаления с std::unique_ptr
чтобы убедиться, что файл закрывается на всех возможных выходах.
Также обратите внимание, что не рекомендуется использовать цикл while(eof(...))
по нескольким причинам. Один из них не установлен в случае ошибки. Больше информации здесь.
// 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");
сотни раз в моей системе не выдает ошибку с этим кодом.
Других решений пока нет …