I am encountering an issue with the boost beast websocket stream. The issue occurs intermittently when I try to write to a stream in which the remote endpoint has stopped responding (specifically due to the remote being physically disconnected from the network).
When this issue occurs, a synchronous stream.write() call eventually hangs for a very long time (minutes) until the socket ultimately closes. I understand that this behavior is likely because my program continues to write to the stream without acks from the remote until the send buffer is full. I am wondering if there is a way to either apply a timeout to the write call, or if there is an interface more along the lines of stream.try_write() where I can raise error handling to the user-level.
I do realize that one option is to use the async_write interface. However, I am concerned that this will negatively impact my send performance by deferring the socket write operation until the next iteration of io_context.
Below is a stack-trace of the thread when the call has hung.
#0 0x00007f468cf33624 in poll () from /lib64/libc.so.6
#1 0x000000000043e5a7 in boost::asio::detail::socket_ops::poll_write (ec=..., msec=-1, state=0 '\000', s=16)
at /usr/include/boost/asio/detail/impl/socket_ops.ipp:1898
#2 boost::asio::detail::socket_ops::sync_send (ec=..., all_empty=<optimized out>, flags=0, count=<optimized out>, bufs=0x7fff43c17e20,
state=<optimized out>, s=<optimized out>) at /usr/include/boost/asio/detail/impl/socket_ops.ipp:1224
#3 boost::asio::detail::reactive_socket_service_base::send<boost::asio::detail::prepared_buffers<boost::asio::const_buffer, 64ul> > (impl=...,
buffers=..., ec=..., this=<optimized out>, flags=0) at /usr/include/boost/asio/detail/reactive_socket_service_base.hpp:245
#4 0x0000000000481c71 in boost::asio::basic_stream_socket<boost::asio::ip::tcp>::write_some<boost::asio::detail::prepared_buffers<boost::asio::const_buffer, 64ul> > (ec=..., buffers=..., this=0x108ad50) at /usr/include/boost/asio/buffer.hpp:941
#5 boost::asio::detail::write_buffer_sequence<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::beast::buffers_cat_view<boost::asio::mutable_buffer, boost::beast::buffers_prefix_view<boost::beast::buffers_suffix<boost::beast::basic_multi_buffer<std::allocator<char> >::const_buffers_type> > >, boost::beast::buffers_cat_view<boost::asio::mutable_buffer, boost::beast::buffers_prefix_view<boost::beast::buffers_suffix<boost::beast::basic_multi_buffer<std::allocator<char> >::const_buffers_type> > >::const_iterator, boost::asio::detail::transfer_all_t> (completion_condition=..., ec=..., buffers=..., s=...)
at /usr/include/boost/asio/impl/write.hpp:53
#6 boost::asio::write<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::beast::buffers_cat_view<boost::asio::mutable_buffer, boost::beast::buffers_prefix_view<boost::beast::buffers_suffix<boost::beast::basic_multi_buffer<std::allocator<char> >::const_buffers_type> > >, boost::asio::detail::transfer_all_t> (ec=..., buffers=..., s=..., completion_condition=...) at /usr/include/boost/asio/impl/write.hpp:69
#7 boost::asio::write<boost::asio::basic_stream_socket<boost::asio::ip::tcp>, boost::beast::buffers_cat_view<boost::asio::mutable_buffer, boost::beast::buffers_prefix_view<boost::beast::buffers_suffix<boost::beast::basic_multi_buffer<std::allocator<char> >::const_buffers_type> > > > (ec=..., buffers=..., s=...)
at /usr/include/boost/asio/impl/write.hpp:92
#8 boost::beast::websocket::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >::write_some<boost::beast::basic_multi_buffer<std::allocator<char> >::const_buffers_type> (this=this@entry=0x108ad50, fin=fin@entry=true, buffers=..., ec=...) at /usr/include/boost/beast/websocket/impl/write.ipp:625
#9 0x000000000042c5e1 in boost::beast::websocket::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >::write<boost::beast::basic_multi_buffer<std::allocator<char> >::const_buffers_type> (ec=..., buffers=..., this=0x108ad50)