您可以为 Asio 的 read_until 设置字节限制吗?
Can you set a byte-limit for Asio's read_until?
我正在使用 boost::asio::read_until
从套接字读取数据,直到收到 "<EOF>"
。但是,有人可以发送数十亿字节,直到系统用完 RAM 并不得不关闭。
为避免这种情况,我想将限制设置为 read_until
。喜欢 "read until "<EOF>"
or until 10MB are reached".
是否有使用 read_until
的简单解决方案,或者我是否必须切换到 read
并在收到 "<EOF>"
时手动结束阅读?
@sehe 有一个很好的答案,允许在 EOF 或读取特定数量的字节时停止。我的版本稍微复杂一些,但还允许在任何定界符处停止。
您可以 construct 您的 boost::asio::streambuf 使用最大尺寸参数:
The constructor for basic_streambuf accepts a size_t argument specifying the maximum of the sum of the sizes of the input sequence and output sequence. During the lifetime of the basic_streambuf object, the following invariant holds:
size() <= max_size()
Any member function that would, if successful, cause the invariant to be violated shall throw an exception of class std::length_error.
或者您可以使用此重载:
template<
typename SyncReadStream,
typename Allocator,
typename MatchCondition>
std::size_t read_until(
SyncReadStream & s,
boost::asio::basic_streambuf< Allocator > & b,
MatchCondition match_condition,
boost::system::error_code & ec,
typename enable_if< is_match_condition< MatchCondition >::value >::type * = 0);
匹配条件函数看起来有点像这样:
using iterator = buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>;
/**
\brief Make read_until stop when either:
* the stop character was found
* more than 100MB have been read
*/
pair<iterator, bool> match_condition(iterator begin, iterator end) {
// to much data?
if(end - begin > 100*1024*1024) {
return std::make_pair(begin, true);
}
// try and find stop character
for(auto i = begin; i < end; i++) {
auto c = i.rdbuf()->sgetc();
if(c == STOP_CHARACTER) {
return std::make_pair(i, true);
}
}
return std::make_pair(begin, false);
}
(使用 multi-character 定界符进行这项工作留作 reader 的练习)
只需使用 transfer_exactly
即可 也 在 EOF 或缓冲区满时停止:
auto transferred = read(s, sb, transfer_exactly(10u<<20), ec);
#include <boost/asio.hpp>
#include <iostream>
using namespace boost::asio;
using namespace ip;
int main() {
boost::system::error_code ec;
io_service svc;
tcp::socket s(svc);
s.connect(tcp::endpoint(address_v4::loopback(), 6767));
streambuf sb;
auto transferred = read(s, sb, transfer_exactly(10u<<20), ec);
std::cerr << "read " << transferred << " till " << ec.message() << "\n";
}
我正在使用 streambuf 限制设置相同的限制。示例代码(使用协程):
try {
boost::asio::streambuf req_buf(100 * 1024); //Limit memory for headers
boost::asio::async_read_until(*sock, req_buf, "\r\n\r\n", yield);
}catch(boost::system::system_error &e) {
if( e.code() == boost::asio::error::make_error_code(boost::asio::error::misc_errors::not_found) )
log("HTTP Connection close: cannot find headers end");
//..
}
就是这样。您可以在读取回调中检查错误代码,并在读取缓冲区中找不到搜索元素时获取特定错误。
我正在使用 boost::asio::read_until
从套接字读取数据,直到收到 "<EOF>"
。但是,有人可以发送数十亿字节,直到系统用完 RAM 并不得不关闭。
为避免这种情况,我想将限制设置为 read_until
。喜欢 "read until "<EOF>"
or until 10MB are reached".
是否有使用 read_until
的简单解决方案,或者我是否必须切换到 read
并在收到 "<EOF>"
时手动结束阅读?
@sehe 有一个很好的答案,允许在 EOF 或读取特定数量的字节时停止。我的版本稍微复杂一些,但还允许在任何定界符处停止。
您可以 construct 您的 boost::asio::streambuf 使用最大尺寸参数:
The constructor for basic_streambuf accepts a size_t argument specifying the maximum of the sum of the sizes of the input sequence and output sequence. During the lifetime of the basic_streambuf object, the following invariant holds:
size() <= max_size()
Any member function that would, if successful, cause the invariant to be violated shall throw an exception of class std::length_error.
或者您可以使用此重载:
template<
typename SyncReadStream,
typename Allocator,
typename MatchCondition>
std::size_t read_until(
SyncReadStream & s,
boost::asio::basic_streambuf< Allocator > & b,
MatchCondition match_condition,
boost::system::error_code & ec,
typename enable_if< is_match_condition< MatchCondition >::value >::type * = 0);
匹配条件函数看起来有点像这样:
using iterator = buffers_iterator<basic_streambuf<Allocator>::const_buffers_type>;
/**
\brief Make read_until stop when either:
* the stop character was found
* more than 100MB have been read
*/
pair<iterator, bool> match_condition(iterator begin, iterator end) {
// to much data?
if(end - begin > 100*1024*1024) {
return std::make_pair(begin, true);
}
// try and find stop character
for(auto i = begin; i < end; i++) {
auto c = i.rdbuf()->sgetc();
if(c == STOP_CHARACTER) {
return std::make_pair(i, true);
}
}
return std::make_pair(begin, false);
}
(使用 multi-character 定界符进行这项工作留作 reader 的练习)
只需使用 transfer_exactly
即可 也 在 EOF 或缓冲区满时停止:
auto transferred = read(s, sb, transfer_exactly(10u<<20), ec);
#include <boost/asio.hpp>
#include <iostream>
using namespace boost::asio;
using namespace ip;
int main() {
boost::system::error_code ec;
io_service svc;
tcp::socket s(svc);
s.connect(tcp::endpoint(address_v4::loopback(), 6767));
streambuf sb;
auto transferred = read(s, sb, transfer_exactly(10u<<20), ec);
std::cerr << "read " << transferred << " till " << ec.message() << "\n";
}
我正在使用 streambuf 限制设置相同的限制。示例代码(使用协程):
try {
boost::asio::streambuf req_buf(100 * 1024); //Limit memory for headers
boost::asio::async_read_until(*sock, req_buf, "\r\n\r\n", yield);
}catch(boost::system::system_error &e) {
if( e.code() == boost::asio::error::make_error_code(boost::asio::error::misc_errors::not_found) )
log("HTTP Connection close: cannot find headers end");
//..
}
就是这样。您可以在读取回调中检查错误代码,并在读取缓冲区中找不到搜索元素时获取特定错误。