1

My goal is to register to a websocket service to get real-time company quotations.

So I based my code on the following example, by mostly calling (again) async_read, once we receive a quotation to accept futures quotation:

https://www.boost.org/doc/libs/master/libs/beast/example/websocket/client/async-ssl/websocket_client_async_ssl.cpp

The problem is when I am waiting for a new quotation (who could take sometimes minutes or hours for small companies), the program is blocked waiting for a message and I do not have the opportunity to ask for another company.

I tried to use the "post" function to call again async_write in the good context thread but the program crashed.

Is there any way to force the completion of callback on_read, to have then the opportunity to send a new message?

Here is the function I modified (simplified without mutexes):

void
    on_read(
        beast::error_code ec,
        std::size_t bytes_transferred)
    {
        boost::ignore_unused(bytes_transferred);

        if(ec)
            return fail2(ec, "read");

        
        std::string mycontent = beast::buffers_to_string(buffer_.data());
        cout << mycontent << endl;
        buffer_.clear();
        
        ws_.async_read(
            buffer_,
            beast::bind_front_handler(
                &session::on_read,
                shared_from_this()));
    }

    void subscribe(const std::string &symbol)
    {
        // We save the message in the queue
        std::string text = "{\"action\": \"subscribe\", \"symbols\": \"" + symbol + "\"}";
        msgqueue_.push_back(text);
        boost::asio::post(ioc_, beast::bind_front_handler(&session::_subscription_to_post, shared_from_this()));
    }

    void _subscription_to_post()
    {
        if (msgqueue_.empty())
            return;

        // We send the message
        ws_.async_write(
            net::buffer(msgqueue_.front()),
            beast::bind_front_handler(
                &session::on_write,
                shared_from_this()));
        msgqueue_.pop_front();
    }

And the program crashes immediately when trying to async_write.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
moochy
  • 11
  • 2

1 Answers1

0

The problem is when I am waiting for a new quotation [...] the program is blocked waiting for a message

It isn't technically blocked because you are using async_read

I tried to use the "post" function to call again async_write in the good context thread, but the program crashed.

That means you're doing something wrong. You can post a question with your self-contained minimal code, and we can tell you what is wrong.

In general, you can use a single read operation and a single write operation concurrently (as in: in flight, asynchronously, you still need to synchronize threads accessing all related resources).

Typically, you have a single async-read-chain active at all times, and a outbound message-queue that is drained by a single async-write chain (that obviously ends when the queue is empty, so needs to be initiated when the first outbound message is queued).

I have many answers on this site (literally dozens) that you may be able to find by search for outbox or outbox_ e.g. Keep in mind that the majority of them will deal with plain (ssl) sockets intead of websockets, but the pattern practically the same.

Is there any way to force the completion of callback on_read, to have then the opportunity to send a new message ?

You can technically cancel() it, which completes it with operation_aborted. But that is not what you need. You want full-duplex, so writing cancel() is the opposite of what you want.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks for your answer. I added a little piece of code of the functions I modified – moochy Feb 11 '23 at 02:00
  • In my example, the context is started in a thread, and the "subscribe" fonction" is called from another thread (I have removed mutexes to simplify the reading) – moochy Feb 11 '23 at 02:29
  • Please don't remove crucial things like thread synchronization. It's highly likely that it contributes to your issue. In fact, make the code self-contained. There's really no reason to make people guess/write your code again just to answer. – sehe Feb 11 '23 at 16:07
  • 1
    As proposed, I completely isolated this weekend the code of my websocket management from my large project, and to my surprise it worked as you expected. I dug my full program, and discovered that I had memory corruption somewhere else, with no obvious other effect than crashing my websocket part when trying to write a new message. So thanks to have requested a fully running example, it made me point the problem. – moochy Feb 13 '23 at 14:48
  • @moochy Good work! I hope you celebrated the moment. I know the feeling, and yes, this is why I do self-contained tests all the time while prototyping and/or debugging – sehe Feb 13 '23 at 15:34