Я использую оболочку boost::beast
доменного сокета unix. моя платформа 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 ? или, возможно, это какое-то определение на системном уровне?
спасибо
Я не вижу здесь звериных типов. Это все исключительно Asio.
Кроме того, streambuf
моделирует концепцию DynamicBuffer
. У него нет фиксированного размера, поэтому ваше утверждение не соответствует действительности.
Наконец, какой бы большой ни была начальная емкость streambuf
, это не принесет вам особой пользы, потому что вы указываете async_read
на 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]
Как видите, размер буфера зависит от ОС, которая на самом деле неплохо масштабирует его в соответствии с требованиями.
Итак, вместо transfer_at_least
используйте любой минимум, который вы считаете разумным:
while (auto n = async_read(s, buf, net::transfer_at_least(1024*1024), yield))
std::cout << "Read: " << n << " (cumulative: " << buf.size() << ")"
<< std::endl;
Вместо этого печатает:
Read: 1048576 (cumulative: 1048576)
Read: 1048576 (cumulative: 2097152)
Read: 1063342 (cumulative: 3160494)
Read: 1086266 (cumulative: 4246760)
...
Read: 1086266 (cumulative: 969962524)
Read: 1102650 (cumulative: 971065174)
Или, если вы согласны читать до EOF:
while (auto n = async_read(s, buf, yield[ec])) {
std::cout << ec.message() << ": " << n
<< " (cumulative: " << buf.size() << ")" << std::endl;
if (ec.failed())
break;
}
Обратите внимание, что мы незаметно добавили проверку error_code, чтобы не пропустить всю передачу из-за EOF. Теперь печатает:
End of file: 971578000 (cumulative: 971578000)
Наконец, вы можете ограничить максимальную емкость, скажем, до 50 МБ:
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;
}
Теперь мы не можем заставить кормить словари, чтобы нам не хватило памяти:
Success: 52428800 (cumulative: 52428800)
Warning: message truncated
Добавлено несколько альтернативных подходов, позволяющих передавать разные «единицы». Также, как читать «бесконечно» и, наконец, как защититься от злого умысла/убегания данных, установив лимит.