如何复制或重用boost :: asio :: streambuf? [英] How copy or reuse boost::asio::streambuf?
问题描述
我正在Boost Asio上实现具有一些业务逻辑的http代理服务器.
I'm implementing http proxy server with some business logic on boost asio.
在(1)点中, boost :: asio :: streambuf response _ 包含http标头和http正文的一部分.
In point (1) boost::asio::streambuf response_ contains http headers and part of http body.
使用 http_response :: parse 缓冲区解析后, boost :: asio :: streambuf response _ 为空.
After parsing with http_response::parse buffer boost::asio::streambuf response_ is empty.
在(2),我检查所有业务逻辑并读取正文,如果标头中有 Content-Length 标头.
At (2) i check all business logic and read body if there was Content-Length header in headers.
然后,如果 response _ 数据符合特定条件,我想将原始的 response _ 缓冲区发送到另一个套接字(3).
Then if response_ data fits specific condtions i want to send the original response_ buffer to another socket (3).
问题是解析后缓冲区为空. 有没有办法复制 boost :: asio :: streambuf 以重复使用数据?
The problem is that buffer is empty after parsing. Is there a way to copy boost::asio::streambuf to reuse data?
void http_response::parse(boost::asio::streambuf& buffer)
{
std::istream response_stream(&buffer);
response_stream >> version_;
response_stream >> status_code_;
response_stream >> status_message_;
std::string key;
std::string value;
std::string header;
std::getline(response_stream, header);
while (std::getline(response_stream, header) && header != "\r") {
header.resize(header.size() - 1);
std::size_t found = header.find(':');
if (found != std::string::npos) {
key = header.substr(0, found);
value = header.substr(found + 2);
headers_[key] = value;
}
}
}
bool go(const std::string& hostname, const std::string& path,
const std::string& server, int port,
boost::asio::io_service::strand& strand,
boost::asio::yield_context& yield)
{
...
http_response response;
boost::asio::streambuf response_;
// async read http header from socket
std::clog << "<- " << sequence_ << " schedule async_read_until head" << std::endl;
boost::asio::async_read_until(socket_, response_, "\r\n\r\n", yield[err]);
check_error_and_timeout(err, timeout_);
// 1. response_.size() == 512 here
response.parse(response_);
// 2. response_.size() == 0 empty here
// using headers for business logic check
...
// read http body if Content-Length > 0
const std::string str_content_length = response.get_header("Content-Length", "");
const size_t content_length = std::stoi(str_content_length);
if(!str_content_length.empty() && content_length > response_.size())
{
std::clog << "<- " << sequence_ << " schedule async_read body" << std::endl;
boost::asio::async_read(socket_, response_,
boost::asio::transfer_at_least(content_length - response_.size()),
yield[err]);
check_error_and_timeout(err, timeout_);
}
// 3. after read all header and body write all data to server sock
boost::asio::async_write(server_socket_, response_, yield[err]);
}
推荐答案
One can use boost::asio::buffer_copy()
to copy the contents of Asio buffers. This can be convenient if, for example, one wishes to copy the contents of one streambuf
to another streambuf
.
boost::asio::streambuf source, target;
...
std::size_t bytes_copied = buffer_copy(
target.prepare(source.size()), // target's output sequence
source.data()); // source's input sequence
// Explicitly move target's output sequence to its input sequence.
target.commit(bytes_copied);
可以使用类似的方法将streambuf
复制到Asio支持可变缓冲区的任何类型.例如,将内容复制到std::vector<char>
:
A similar approach can be used to copy from a streambuf
into any type for which Asio supports mutable buffers. For example, copying content into a std::vector<char>
:
boost::asio::streambuf source;
...
std::vector<char> target(source.size());
buffer_copy(boost::asio::buffer(target), source.data());
一个值得注意的例外是Asio不支持为std::string
返回可变的缓冲区.但是,仍然可以通过迭代器完成复制到std::string
的操作:
One notable exception is that Asio does not support returning a mutable buffer for std::string
. However, one can still accomplish copying into std::string
via iterators:
boost::asio::streambuf source;
...
std::string target{
buffers_begin(source.data()),
buffers_end(source.data())
};
以下是示例演示将内容从boost::asio::streambuf
复制到其他各种类型:
Here is an example demonstrating copying contents from boost::asio::streambuf
into various other types:
#include <iostream>
#include <string>
#include <vector>
#include <boost/asio.hpp>
int main()
{
const std::string expected = "This is a demo";
// Populate source's input sequence.
boost::asio::streambuf source;
std::ostream ostream(&source);
ostream << expected;
// streambuf example
{
boost::asio::streambuf target;
target.commit(buffer_copy(
target.prepare(source.size()), // target's output sequence
source.data())); // source's input sequence
// Verify the contents are equal.
assert(std::equal(
buffers_begin(target.data()),
buffers_end(target.data()),
begin(expected)
));
}
// std::vector example
{
std::vector<char> target(source.size());
buffer_copy(boost::asio::buffer(target), source.data());
// Verify the contents are equal.
assert(std::equal(begin(target), end(target), begin(expected)));
}
// std::string example
{
// Copy directly into std::string. Asio does not support
// returning a mutable buffer for std::string.
std::string target{
buffers_begin(source.data()),
buffers_end(source.data())
};
// Verify the contents are equal.
assert(std::equal(begin(target), end(target), begin(expected)));
}
}
这篇关于如何复制或重用boost :: asio :: streambuf?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!