我正在使用boost::asio::read_until
从套接字读取,直到收到"<EOF>"
为止。但是,有人可能会发送数十亿和数十亿字节,直到系统耗尽RAM并且必须关闭。
为避免这种情况,我想将限制设为read_until
。喜欢&#34;阅读"<EOF>"
或直到达到10MB&#34;。
使用read_until
是否有一个简单的解决方案,或者我必须切换到read
并在收到"<EOF>"
时手动结束阅读?
答案 0 :(得分:6)
@sehe有一个很好的答案,允许停止EOF或读取特定数量的字节。我的版本稍微复杂一些,但另外允许在任何分隔符上停止。
你可以使用max size参数construct你的boost :: asio :: streambuf:
basic_streambuf的构造函数接受size_t参数,该参数指定输入序列和输出序列的大小总和的最大值。在basic_streambuf对象的生命周期中,以下不变量成立:
size() <= max_size()
如果成功导致违反不变量的任何成员函数将抛出类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);
}
(使用多字符分隔符进行此操作留给读者练习)
答案 1 :(得分:6)
只需使用也停在EOF或缓冲区已满的transfer_exactly
:
auto transferred = read(s, sb, transfer_exactly(10u<<20), ec);
<强> Live On Coliru 强>
#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";
}
答案 2 :(得分:0)
我使用 streambuf 限制设置相同的限制。示例代码(使用协同程序):
dbCommand.CommandText = "ALTER TABLE USERS MODIFY (USER_ID NUMBER(18,0))";
多数民众赞成。您可以检查读取回调中的错误代码,并在读取缓冲区中找不到搜索元素时获取特定错误。