basiliscos / cpp-bredis

Boost::ASIO low-level redis client (connector)
MIT License
147 stars 36 forks source link

Clarification regarding multiple messages #48

Closed silviuzil closed 3 years ago

silviuzil commented 3 years ago

Hi,

There is some issue that I can't figure out from the documentation: when multiple messages are streamed in and the buffer contains more then one message, what's the correct way of using async_read to ensure that all messages are handled and none is lost. Is it handled within bredis or should I adapt on my side?

Thanks, Silviu

basiliscos commented 3 years ago

Hi,

This is your responsibility to manage rx_buff. You should allocate it, than feed it to async_read with the callback. The callback will tell you how many bytes it parsed (r.consumed). Then, when you done with the result, you should free them (rx_buff.consume(r.consumed)),

silviuzil commented 3 years ago

Hi,

Thanks, that's exactly what I do. My message size is 35 bytes, and that's what I get in r.consumed. However, in some cases for the buffer size is some multiple of 35, e.g. 70 or 105 bytes. I assume I have several messages in the buffer. Single consume removes 35 bytes. I just want to verify that the other messages are not lost and will be handled by the next async_read. Thanks for your help!

Silviu

basiliscos commented 3 years ago

Yep, it should be handled on the next asyn_read call, as soon as they are staying in the buffer :+1:

Cheers!

asantoni commented 3 years ago

FWIW, I have this exact problem but I don't understand when the extra bytes are supposed to get processed. If I check the streambuf.size() and see that it has extra data in it, what should we do? If I call async_read again manually, my connection hangs forever since the callback is triggered by data coming in on the socket. I don't seem to get a second callback call automatically from bredis. Any tips would be greatly appreciated.

basiliscos commented 3 years ago

The API is quite simple:

rx_buff = ... ; // define and hold it somewhere, i.e. make sure it is not destroyed
connectino.async_read(rx_buff, [&](const sys::error_code &, result_t &&r) {
                // inspect the result
                rx_buff.consume(r.consumed); // done 
                if (ok) read_more();
            });

So, it is basilcally async_read(rx_buff) and rx_buff.consume() with the your code in-between. It can be wrapped into some funtion, i.e. read_more() , so in the callback, when everything is ok, read_more is invoked again to read the next redis command.

The callback will NOT be invoked until it is fully read or some error occurs. If redis sends no data, then callback is not invoked.