如何复制或重复使用boost :: asio :: streambuf
How copy or reuse boost::asio::streambuf?
我正在使用Boost Asio上的某些业务逻辑实现HTTP代理服务器。
在第(1)点 boost :: Asio :: streamBuf响应_ 包含HTTP标题和HTTP主体的一部分。
用 http_response :: parse buffer boost :: asio :: asseambuf响应_ 是空的。
在(2)我检查所有业务逻辑,并阅读身体,如果 eNcts-Length 标题中的标题。
然后,如果响应_ 数据适合我要将原始响应发送的特定条件_ buffer发送到另一个插座(3)。
问题是解析后的缓冲区是空的。有没有办法复制 boost :: asio :: streambuf 重复使用数据?
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_, "rnrn", 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]);
}
可以使用boost::asio::buffer_copy()
复制ASIO缓冲区的内容。例如,如果一个人希望将一个streambuf
的内容复制到另一个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>
:
boost::asio::streambuf source;
...
std::vector<char> target(source.size());
buffer_copy(boost::asio::buffer(target), source.data());
一个值得注意的例外是ASIO不支持返回std::string
的可突变缓冲区。但是,仍然可以通过迭代器完成复制到std::string
:
boost::asio::streambuf source;
...
std::string target{
buffers_begin(source.data()),
buffers_end(source.data())
};
这是一个示例,将boost::asio::streambuf
复制内容的复制内容展示为其他类型:
#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)));
}
}
首先,您不能复制 streambuf - 它已删除复制构造函数。
我应该建议使用 asio :: buffer 使用自己的缓冲区并解析。但是,您将无法使用 async_read_until 。另外,您可以将其消费到自己的缓冲区中,然后在需要时发送。
lifehack:您可以在不使用buffer_cast消耗数据的情况下获取数据,但请注意,它不是安全的方法,因为它没有记录并且可能破裂了(但对我有很多次和许多提升升级):
// req_buf is a streambuf
const char *req_data = boost::asio::buffer_cast<const char *>( req_buf.data() );
auto sz = req_buf.size();
再次注意:此演员阵容起作用是因为 streambuf 实现某些概念,但没有直接记录。另外,请记住 REQ_DATA 在任何 req_buf modify。
- 理解boost::asio-async_read在无需读取内容时的行为
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- boost::asio::steady_timer()与sleep()我应该使用哪一个
- boost::asio如何生成多个协同程序,然后加入它们
- 从 Boost ASIO 获取 epoll 描述符 io_service对象
- 如何在 Boost.Asio 中使用 Zero-copy sendmsg/receive
- 如何使用 Boost Asio 在 Android 上获取我的本地 udp IP 地址?
- 执行时使用 boost::asio::d eadline_timer 时出错
- Boost.Asio/OpenSSL HTTPS GET certificate trouble
- boost::asio data owning `ConstBufferSequence`
- 如何替换此示例代码片段中已弃用的handler_type_t或 boost::asio::handler_type?
- 如何将boost::asio::d eadline_timer 与Qt一起使用?
- 将更高的优先级设置为 boost::asio 线程处理进程
- Async_read_until限制读取的字节大小(Boost::asio)
- 程序崩溃使用boost::asio
- boost::asio 无法捕获 SIGINT
- TCP 服务器的异步读取使用 boost::asio 打印客户端套接字发送的数据
- 如何在 boost::asio 中将打包的结构作为消息传递?(无序列化)
- 如何使用C++和Boost Asio从HTTP发布请求中获取键值
- std::boost::asio::p ost / dispatch 使用哪个io_context?