我試圖了解如何通過在 boost beast 中呼叫“read_some”函式來限制從 Internet 讀取的資料量。
起點是野獸檔案中的增量讀取示例。從檔案中我了解到真正讀取的資料存盤在 flat_buffer 中。我做了以下實驗:
- 將最大 flat_buffer 的大小設定為 1024
- 連接到一個相對較大(幾 KB)的 html 頁面
- 呼叫 read_some 一次
- 關閉互聯網
- 嘗試將頁面閱讀到最后
由于緩沖區的容量不足以存盤整個頁面,因此我的實驗應該失敗 - 我應該無法讀取整個頁面。盡管如此,它還是成功完成了。這意味著存在一些額外的緩沖區來存盤讀取的資料。但它是做什么用的,我該如何限制它的大小?
UPD 這是我的源代碼:
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/strand.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace net = boost::asio; // from <boost/asio.hpp>
using namespace http;
template<
bool isRequest,
class SyncReadStream,
class DynamicBuffer>
void
read_and_print_body(
std::ostream& os,
SyncReadStream& stream,
DynamicBuffer& buffer,
boost::beast::error_code& ec ) {
parser<isRequest, buffer_body> p;
read_header( stream, buffer, p, ec );
if ( ec )
return;
while ( !p.is_done()) {
char buf[512];
p.get().body().data = buf;
p.get().body().size = sizeof( buf );
read_some( stream, buffer, p, ec );
if ( ec == error::need_buffer )
ec = {};
if ( ec )
return;
os.write( buf, sizeof( buf ) - p.get().body().size );
}
}
int main(int argc, char** argv)
{
try
{
// Check command line arguments.
if(argc != 4 && argc != 5)
{
std::cerr <<
"Usage: http-client-sync <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]\n" <<
"Example:\n" <<
" http-client-sync www.example.com 80 /\n" <<
" http-client-sync www.example.com 80 / 1.0\n";
return EXIT_FAILURE;
}
auto const host = argv[1];
auto const port = argv[2];
auto const target = argv[3];
int version = argc == 5 && !std::strcmp("1.0", argv[4]) ? 10 : 11;
// The io_context is required for all I/O
net::io_context ioc;
// These objects perform our I/O
boost::asio::ip::tcp::resolver resolver(ioc);
beast::tcp_stream stream(ioc);
// Look up the domain name
auto const results = resolver.resolve(host, port);
// Make the connection on the IP address we get from a lookup
stream.connect(results);
// Set up an HTTP GET request message
http::request<http::string_body> req{http::verb::get, target, version};
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Send the HTTP request to the remote host
http::write(stream, req);
// This buffer is used for reading and must be persisted
beast::flat_buffer buffer;
boost::beast::error_code ec;
read_and_print_body<false>(std::cout, stream, buffer, ec);
}
catch(std::exception const& e)
{
std::cerr << "Error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
uj5u.com熱心網友回復:
作業系統的 TCP IP 堆疊顯然需要緩沖資料,所以這很可能是它被緩沖的地方。
測驗所需場景的方法:
住在科利魯
#include <boost/beast.hpp>
#include <iostream>
#include <thread>
namespace net = boost::asio;
namespace beast = boost::beast;
namespace http = beast::http;
using net::ip::tcp;
void server()
{
net::io_context ioc;
tcp::acceptor acc{ioc, {{}, 8989}};
acc.listen();
auto conn = acc.accept();
http::request<http::string_body> msg(
http::verb::get, "/", 11, std::string(20ull << 10, '*'));
msg.prepare_payload();
http::request_serializer<http::string_body> ser(msg);
size_t hbytes = write_header(conn, ser);
// size_t bbytes = write_some(conn, ser);
size_t bbytes = write(conn, net::buffer(msg.body(), 1024));
std::cout << "sent " << hbytes << " header and " << bbytes << "/"
<< msg.body().length() << " of body" << std::endl;
// closes connection
}
namespace {
template<bool isRequest, class SyncReadStream, class DynamicBuffer>
auto
read_and_print_body(
std::ostream& /*os*/,
SyncReadStream& stream,
DynamicBuffer& buffer,
boost::beast::error_code& ec)
{
struct { size_t hbytes = 0, bbytes = 0; } ret;
http::parser<isRequest, http::buffer_body> p;
//p.header_limit(8192);
//p.body_limit(1024);
ret.hbytes = read_header(stream, buffer, p, ec);
if(ec)
return ret;
while(! p.is_done())
{
char buf[512];
p.get().body().data = buf;
p.get().body().size = sizeof(buf);
ret.bbytes = http::read_some(stream, buffer, p, ec);
if(ec == http::error::need_buffer)
ec = {};
if(ec)
break;
//os.write(buf, sizeof(buf) - p.get().body().size);
}
return ret;
}
}
void client()
{
net::io_context ioc;
tcp::socket conn{ioc};
conn.connect({{}, 8989});
beast::error_code ec;
beast::flat_buffer buf;
auto [hbytes, bbytes] = read_and_print_body<true>(std::cout, conn, buf, ec);
std::cout << "received hbytes:" << hbytes << " bbytes:" << bbytes
<< " (" << ec.message() << ")" << std::endl;
}
int main()
{
std::jthread s(server);
std::this_thread::sleep_for(std::chrono::seconds(1));
std::jthread c(client);
}
印刷
sent 41 header and 1024/20480 of body
received 1065 bytes of message (partial message)
旁注
你開始你的問題:
我試圖了解如何限制從 Internet 讀取的資料量
這是內置在 Beast 中的
通過在 boost beast 中呼叫“read_some”函式。
為了限制讀取的資料總量,您不必read_some在回圈中使用(http::read根據定義已經完全這樣做了)。
例如,對于上面的示例,如果將20ull<<10(20 KiB)替換為20ull<<20(20 MiB),您將超過默認大小限制:
http::request<http::string_body> msg(http::verb::get, "/", 11,
std::string(20ull << 20, '*'));
在Coliru現場列印
sent 44 header and 1024/20971520 of body
received hbytes:44 bbytes:0 (body limit exceeded)
您還可以設定自己的決議器限制:
http::parser<isRequest, http::buffer_body> p;
p.header_limit(8192);
p.body_limit(1024);
哪個列印Live On Coliru:
發送 41 標頭和 1024/20480 接收的正文 hbytes:41 bbytes:0 (超出正文限制)
如您所見,它甚至知道在讀取標頭后使用標頭中的content-length資訊拒絕請求。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/488422.html
