Boost C++ 库

“……世界上最受尊敬和设计最精良的 C++ 库项目之一。” Herb SutterAndrei Alexandrescu, C++ 编码标准

PrevUpHomeNext

发送子进程输出 💡

有时,需要发送的消息体不方便用单个容器来描述。 例如,当实现 HTTP 中继功能时,一个健壮的实现需要单独呈现来自下游主机的可用 body 缓冲区。 这些缓冲区应该是固定大小的,否则会在将完整消息体转发到上游主机之前,产生不必要且低效的读取完整消息体的负担。

为了支持这些用例,提供了 body 类型 buffer_body。此 body 使用调用者提供的指针和大小,而不是拥有的容器。 要使用此 body,请实例化序列化器的一个实例,并在调用流写入函数之前,填写指针和大小字段。

此示例从子进程读取数据,并将输出作为 HTTP 响应发回。进程的输出在可用时立即发送。

/** Send the output of a child process as an HTTP response.

    The output of the child process comes from a @b SyncReadStream. Data
    will be sent continuously as it is produced, without the requirement
    that the entire process output is buffered before being sent. The
    response will use the chunked transfer encoding.

    @param input A stream to read the child process output from.

    @param output A stream to write the HTTP response to.

    @param ec Set to the error, if any occurred.
*/
template<
    class SyncReadStream,
    class SyncWriteStream>
void
send_cgi_response(
    SyncReadStream& input,
    SyncWriteStream& output,
    error_code& ec)
{
    static_assert(is_sync_read_stream<SyncReadStream>::value,
        "SyncReadStream requirements not met");

    static_assert(is_sync_write_stream<SyncWriteStream>::value,
        "SyncWriteStream requirements not met");

    // Set up the response. We use the buffer_body type,
    // allowing serialization to use manually provided buffers.
    response<buffer_body> res;

    res.result(status::ok);
    res.version(11);
    res.set(field::server, "Beast");
    res.set(field::transfer_encoding, "chunked");

    // No data yet, but we set more = true to indicate
    // that it might be coming later. Otherwise the
    // serializer::is_done would return true right after
    // sending the header.
    res.body().data = nullptr;
    res.body().more = true;

    // Create the serializer.
    response_serializer<buffer_body, fields> sr{res};

    // Send the header immediately.
    write_header(output, sr, ec);
    if(ec)
        return;

    // Alternate between reading from the child process
    // and sending all the process output until there
    // is no more output.
    do
    {
        // Read a buffer from the child process
        char buffer[2048];
        auto bytes_transferred = input.read_some(
            boost::asio::buffer(buffer, sizeof(buffer)), ec);
        if(ec == boost::asio::error::eof)
        {
            ec = {};

            // `nullptr` indicates there is no buffer
            res.body().data = nullptr;

            // `false` means no more data is coming
            res.body().more = false;
        }
        else
        {
            if(ec)
                return;

            // Point to our buffer with the bytes that
            // we received, and indicate that there may
            // be some more data coming
            res.body().data = buffer;
            res.body().size = bytes_transferred;
            res.body().more = true;
        }

        // Write everything in the body buffer
        write(output, sr, ec);

        // This error is returned by body_buffer during
        // serialization when it is done sending the data
        // provided and needs another buffer.
        if(ec == error::need_buffer)
        {
            ec = {};
            continue;
        }
        if(ec)
            return;
    }
    while(! sr.is_done());
}

PrevUpHomeNext