I am trying to use boost::beast::websocket::aysnc_write with multiple calls, I did queue for the buffers and in the end of the write, in handle, I pop from the queue and call the write again. I try to run it with 5 calls, but after the pop of the second buffer it stop the run.
I use Boost in version 1.72.0, linux rocky
void Session::do_write(std::string data)
{
std::cout << "do_write" << std::endl;
if (m_isWrite) {
std::cout << "do_write push" << std::endl;
m_queueBufferTx.push(boost::asio::buffer(data));
return;
}
m_bufferTx = boost::asio::buffer(data);
on_write();
}
void Session::on_write()
{
std::cout << "write size " <<m_queueBufferTx.size() << std::endl;
m_isWrite = true;
m_ws.text(m_ws.got_text());
m_ws.async_write(m_bufferTx, beast::bind_front_handler(&Session::handle_write, shared_from_this()));
}
void Session::handle_write(beast::error_code ec, std::size_t bytes_transferred)
{
m_isWrite = false;
std::cout << "finish write size " <<m_queueBufferTx.size() << std::endl;
boost::ignore_unused(bytes_transferred);
if (ec) {
LOGGER(MtLogger::ERROR, "write: " << ec.message() << "n")
return;
}
if (!m_queueBufferTx.empty() && !m_isWrite) {
std::cout << "handle_write pop" << std::endl;
m_isWrite = true;
m_bufferTx = m_queueBufferTx.pop();
on_write();
}
}
in the main i do:
json ex = { { "type", "X400FeCmd" }, { "command", "Disconnection"} };
for (int i = 0; i < 5; ++i){
session->do_write(ex.dump());
}
In the terminal, I see the print:
do_write
write size 0
do_write
do_write push
do_write
do_write push
do_write
do_write push
do_write
do_write push
finish write size 4
handle_write pop
write size 3
I think that the issue is hidden in interplay between this:
if (m_isWrite) {
std::cout << "do_write push" << std::endl;
m_queueBufferTx.push(boost::asio::buffer(data));
return;
}
and this:
std::cout << "write size " <<m_queueBufferTx.size() << std::endl;
m_isWrite = true;
While you’re waiting on
m_ws.async_write(m_bufferTx, beast::bind_front_handler(&Session::handle_write, shared_from_this()));
to complete (and set m_isWrite
to false), your outer loop manages to call do_write
another 4 times. Completion handler handle_write
is executed only afterwards, when it’s already too late. You could verify it be adding a delay in the loop using, for example, boost::asio::deadline_timer
. I don’t fully understand the need of m_isWrite
though, just check if your buffer has something and pop it’s content.