boost :: process redirect stdin,stdout,stderr

时间:2013-12-14 16:01:56

标签: c++ process boost-asio spawn

我为此处发布的代码长度道歉。我正在尝试创建一个类,它使用boost :: process来生成一个进程,在它的stdin上提供一些数据并捕获它的所有stdout&标准错误,

子进程'stdin可能和stdout一样冗长;目标机器没有大量内存,因此每个内存都需要以块的形式处理。

我已经阅读了无数使用boost :: process的例子,但没有找到任何可以解决所有这些问题的例子。我试过结合这些例子但没有成功。我显然错过了一些东西。我将不胜感激任何帮助。

发生的事情是子进程成功生成但没有任何反应。父进程在标记为THUS * 的行上停止。

班级定义:

class CommandProcessor {
public:
    explicit CommandProcessor(const std::string &executable_path, bool slow) :
        executable_path_(executable_path), slow_(slow), in_(io_service_, ::dup(STDIN_FILENO)), out_(io_service_, ::dup(STDOUT_FILENO)), err_(io_service_, ::dup(STDERR_FILENO)) {
    }

private:
    void begin_write_stdin();
    void end_write_stdin(const boost::system::error_code &ec, std::size_t bytes_transferred);
    void begin_read_stdout();
    void end_read_stdout(const boost::system::error_code &ec, std::size_t bytes_transferred);
    void begin_read_stderr();
    void end_read_stderr(const boost::system::error_code &ec, std::size_t bytes_transferred);

public:
    void execute_command(const Command& command);

private:
    boost::filesystem::path executable_path_;bool slow_;
    boost::asio::io_service io_service_;
    boost::asio::posix::stream_descriptor in_;
    boost::asio::posix::stream_descriptor out_;
    boost::asio::posix::stream_descriptor err_;
    std::string stdout_;
    std::string stderr_;
    std::string stdin_buffer_;
    std::array<char, 4096> stdout_buffer_;
    std::array<char, 4096> stderr_buffer_;
    std::vector<std::string>::const_iterator stdin_it_;
    std::vector<std::string>::const_iterator stdin_end_;
};

代码(为简洁起见,我只包括给我带来麻烦的位):

void CommandProcessor::begin_write_stdin() {
    if (stdin_buffer_.size() == 0) {
        for (; stdin_it_ != stdin_end_; stdin_it_++) {
            if (stdin_buffer_.size() + stdin_it_->size() > 4096) {
                break;
            }
            stdin_buffer_ += *stdin_it_;
        }
    }
    if (stdin_buffer_.size() == 0) {
        return;
    }
    in_.async_write_some(boost::asio::buffer(stdin_buffer_),
        boost::bind(&CommandProcessor::end_write_stdin, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void CommandProcessor::end_write_stdin(const boost::system::error_code &ec, std::size_t bytes_transferred __attribute__((unused))) {
    if (!ec) {
        stdin_it_++;
        if (stdin_it_ != stdin_end_) {
            begin_write_stdin();
        }
    }
    in_.close();
}

void CommandProcessor::begin_read_stdout() {
    out_.async_read_some(boost::asio::buffer(stdout_buffer_),
        boost::bind(&CommandProcessor::end_read_stdout, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void CommandProcessor::end_read_stdout(const boost::system::error_code &ec, std::size_t bytes_transferred __attribute__((unused))) {
    if (!ec) {
        stdout_ += stdout_buffer_.data();
        begin_read_stdout();
    }
    out_.close();
}

void CommandProcessor::begin_read_stderr() {
    err_.async_read_some(boost::asio::buffer(stderr_buffer_), boost::bind(&CommandProcessor::end_read_stderr, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}

void CommandProcessor::end_read_stderr(const boost::system::error_code &ec, std::size_t bytes_transferred __attribute__((unused))) {
    if (!ec) {
        stderr_ += stderr_buffer_.data();
        begin_read_stderr();
    }
    err_.close();
}


void CommandProcessor::execute_command(const Command& command) {
    boost::process::context ctx;
    ctx.stdin_behavior = boost::process::capture_stream();
    ctx.stdout_behavior = boost::process::capture_stream();
    ctx.stderr_behavior = boost::process::capture_stream();

    stdin_it_ = command.for_stdin_.begin();
    stdin_end_ = command.for_stdin_.end();

    boost::process::child child(boost::process::launch((executable_path_ / command.executable_name_).string(), command.executable_name_ + command.arguments_, ctx));

    boost::process::pistream &child_stdout(child.get_stdout());
    **** Halts in next statement
    in_.assign(child_stdout.handle().release());
    boost::process::pistream &child_stderr(child.get_stderr());
    err_.assign(child_stderr.handle().release());
    boost::process::postream &child_stdin = child.get_stdin();
    out_.assign(child_stdin.handle().release());

    begin_read_stdout();
    begin_read_stderr();
    begin_write_stdin();

    boost::process::status child_status(child.wait());
    if (child_status.exited()) {
        if (child_status.exit_status() == 0) {
            throw ProcessorException((boost::format("Exec status %d on %s") % child_status.exit_status() % (executable_path_ / command.executable_name_).string()).str());
        }
    } else {
        throw ProcessorException((boost::format("Exec failure on %s") % (executable_path_ / command.executable_name_).string()).str());
    }
}

0 个答案:

没有答案