beast: websocket::read_some blocks after received a Pong message
Hello, websocket::read_some blocks after reading a Pong message (control message) and waiting for the next frame.
What I’am doing: I am using several client websockets. Before I do a read operation on a websocket I am using select to make sure that a read on a socket won’t block. I want to manage my control message like Ping and Pong on my own because the protocol I am using requires specific payload.
- I’m sending a Ping to the server,
- call select on the fd (there will be data because of the pong message from server)
- call read_some, my callback is called and afterwards read_some is blocked because it waits for the next frame after the Pong.
Pseudo code
ws = std::unique_ptr<websocket::stream<tcp::socket>>(new websocket::stream<tcp::socket>(*ioc));
ws->control_callback([this](const websocket::frame_type kind, const beast::string_view payload) {}
ws->handshake(host, "/"); // connect
ws->ping(websocket::ping_data(payload)); // send ping
select(ws->next_layer().native_handle()) // to the select, there will be data, the pong
ws->read_some(flatBuffer, buffer.getRemainingBytes()); // will call callback and blocks afterwards and waiting for more data
In my opinion it’s not a good idea to handle the control messages like ping/pong within the read_some method. It would be better to return like we are reading a normal frame and let the user decide what to do. There is already a method is_message_done() (fin bit). Why not introduce methods like is_message_ping() or is_message_pong() so that the user can check the type of the frame?
I did a small workaround in my git repo: https://github.com/eliot-exdev/boost-beast.git branch ping_pong_fix.
If a ping/pong is received the callback will be called and afterwards return with 0 (nothing read). So the read_some won’t block anymore a I have the needed payload and the information about ping/pong in my callback.
To sum it up: think about if you really want to handle the ping/pong in a read request. If there is a any special payload needed for these messages the user cannot provide it at the moment. Perhaps the underlying protcol needs to consider special timings, … It would be much better to return the payload to the user and give him a hint what the type of frame was received (fin bit, ping bit, pong bit, close might be a special case).
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 18 (8 by maintainers)
Perfect, the penny dropped 😃 Thanks for your patience and help!
Hi Vinnie,
I just tested the async api. It looks good for me. But asio is spawning an second thread internally although I am calling ioc.sun() directly from main (see gdb):
Besides that I looked into the asio code. It also uses select/poll to recognize if an socket is readable (see strace):
Though my idea using select wasn’t that bad. It’s a pity that asio/beast is forcing the user to use the async api just to have non blocking reads. But in the end it’s ok for me to have one more thread per ioc.
Thank you for this great discussion and your work on boost::beast. I think it’s great and it feels right in many ways compared to other libraries.
regards André