I have a boost::beast HTTP server that streams data to a connected client. I'm happy to ignore anything they send to me, so I constantly call async_write without calling async_receive. But I think this causes a problem where I don't notice the client's request to close the socket.
Because I don't ever call async_receive(), I need to set timeout.idle_timeout = none() because writes do not reset the idle timer. timeout.handshake_timeout is 30s by default, and this seems appropriate.
void Session::Accept(Request&& req){
auto timeout = boost::beast::websocket::stream_base::timeout::suggested(
boost::beast::role_type::server // sets handshake_timeout = 30s
);
timeout.idle_timeout = boost::beast::websocket::stream_base::none();
m_client.set_option( timeout );
// accept stuff
Write();
}
void Session::Write(){
m_client.async_write(
m_buffer.data(),
boost::beast::bind_front_handler(
&Session::OnWrite,
shared_from_this()
)
);
}
void Session::OnWrite(
const boost::beast::error_code ec,
std::size_t bytes_transferred
){
if (ec){
std::cerr << "client disconnected with: " << ec.message() << std::endl;
return;
}
PopulateBuffer();
Write();
}
When I use a Javascript client to close the socket, there is a delay (up to 30s) between socket.close() and the socket.onclose function. That's the problem I'm trying to solve.
socket = new WebSocket('ws://...');
socket.onopen = function() {
...
}
socket.onmessage = function(event) {
if (...)
socket.close()
}
socket.onclose = function(event) {
console.log(event)
}
When the socket.onclose slot is finally called, the exit code is 1006 (abnormal -- Connection closed without receiving a close frame). That's a reserved code that cannot be sent along the wire. Therefore it's something the client decided, not something the server sent.
My hypothesis is the client's socket.close() causes something to be sent to the server, and then stops the handshakes, but because I never async_read(), beast's websocket doesn't process the close-request, and it keeps sending data until the handshakes timeout (30s). Upon timeout, it sends a 1006 close reason to the client, and invokes my async_write() handler with a "broken pipe" error-code.
What's the best way to deal with this?
I don't want to call async_receive() because I can't call async_write() again until the async_receive() has finished. And blocking (almost) forever on the useless read will prevent me from sending my steam.
If there is a fast way of detecting of data is available for reading, I could certainly do that. I'm just not sure what method is available.
async_*operations (read,write,ping,pong,close) can be simultaneously pending, assuming they're in the same strand. Therefore, I'll try an asyncread()loop on Monday.