我正在使用boost::beastunix 域套接字的包裝器。我的平臺是 macOS。
首先,我定義了套接字:
boost::asio::local::stream_protocol::socket socket;
我想用它來閱讀最大 2k 的訊息。
boost::asio::streambuf input_streambuf;
...
boost::asio::async_read(socket, input_streambuf,
boost::asio::transfer_at_least(1), yield);
但是,input_streambuf 只有 512 個位元組。
知道我是否可以從 Boost::beast 增加這個限制嗎?或者可能是系統級別的一些定義?
謝謝
uj5u.com熱心網友回復:
我在這里看不到任何野獸型別。這一切都是 Asio 獨有的。
此外,streambuf模型的DynamicBuffer概念。它沒有固定的大小,因此您的宣告不準確。
最后,無論初始容量有streambuf多大,它都不會對您有多大好處,因為您指示async_readto transfer_at_least(1),這意味著底層實作中任何平臺相關的緩沖區都可能導致第一個read_some回傳的緩沖區小得多數量。例如,使用這個簡單的服務器:
住在科利魯
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <iostream>
namespace net = boost::asio;
using U = net::local::stream_protocol;
int main() {
net::thread_pool io;
using net::yield_context;
U::acceptor acc(io, "./test.sock");
acc.listen();
U::socket s = acc.accept();
spawn(io, [&](yield_context yield) { //
net::streambuf buf;
while (auto n = async_read(s, buf, net::transfer_at_least(1), yield))
std::cout << "Read: " << n << " (cumulative: " << buf.size() << ")"
<< std::endl;
});
io.join();
}
使用客戶端時,例如:
netcat -U ./test.sock <<RESP
Hello world
This is Brussels calling
From pool to pool
RESP
將列印例如:
Read: 55 (cumulative: 55)
但是在netcat -U ./test.sock互動運行時:
Read: 12 (cumulative: 12)
Read: 30 (cumulative: 42)
Read: 17 (cumulative: 59)
事實上,我們可以毫不夸張地向它扔一千本字典:
for a in {1..1000}; do cat /etc/dictionaries-common/words; done | netcat -U ./test.sock
輸出是:
Read: 512 (cumulative: 512)
Read: 512 (cumulative: 1024)
Read: 512 (cumulative: 1536)
Read: 512 (cumulative: 2048)
Read: 512 (cumulative: 2560)
Read: 1536 (cumulative: 4096)
Read: 512 (cumulative: 4608)
Read: 3584 (cumulative: 8192)
Read: 512 (cumulative: 8704)
Read: 7680 (cumulative: 16384)
Read: 512 (cumulative: 16896)
Read: 15872 (cumulative: 32768)
Read: 512 (cumulative: 33280)
Read: 32256 (cumulative: 65536)
Read: 512 (cumulative: 66048)
Read: 65024 (cumulative: 131072)
Read: 512 (cumulative: 131584)
Read: 65536 (cumulative: 197120)
...
Read: 49152 (cumulative: 971409238)
Read: 49152 (cumulative: 971458390)
Read: 49152 (cumulative: 971507542)
Read: 49152 (cumulative: 971556694)
Read: 21306 (cumulative: 971578000)
terminate called after throwing an instance of 'boost::wrapexcept<boost::exception_detail::current_exception_std_exception_wrapper<std::runtime_error> >'
what(): End of file [asio.misc:2]
As you can see, the size of the buffer is dependent on the OS, which actually does a decent job of scaling it up to requirements.
Improving The Instructions
So, instead of transfer_at_least use whatever minimum you found reasonable:
while (auto n = async_read(s, buf, net::transfer_at_least(1024*1024), yield))
std::cout << "Read: " << n << " (cumulative: " << buf.size() << ")"
<< std::endl;
Prints instead:
Read: 1048576 (cumulative: 1048576)
Read: 1048576 (cumulative: 2097152)
Read: 1063342 (cumulative: 3160494)
Read: 1086266 (cumulative: 4246760)
...
Read: 1086266 (cumulative: 969962524)
Read: 1102650 (cumulative: 971065174)
Or if you are content to read until EOF:
while (auto n = async_read(s, buf, yield[ec])) {
std::cout << ec.message() << ": " << n
<< " (cumulative: " << buf.size() << ")" << std::endl;
if (ec.failed())
break;
}
Note that subtly we added error_code checking so we don't miss the whole transfer due to EOF. Now prints:
End of file: 971578000 (cumulative: 971578000)
Finally, you may want to limit maximum capacity, say to 50 Mib:
constexpr size_t _50MiB = 50<<20;
net::streambuf buf(_50MiB);
boost::system::error_code ec;
while (auto n = async_read(s, buf, yield[ec])) {
std::cout << ec.message() << ": " << n
<< " (cumulative: " << buf.size() << ")" << std::endl;
if (ec.failed())
break;
}
if (ec != net::error::eof && buf.size() == _50MiB) {
std::cout << "Warning: message truncated" << std::endl;
}
Now we can't force feed dictionaries to run us out of memory:
Success: 52428800 (cumulative: 52428800)
Warning: message truncated
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/447349.html
