首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Boost (Beast) websocket:同步写入挂起

Boost (Beast) websocket:同步写入挂起
EN

Stack Overflow用户
提问于 2018-09-24 06:35:08
回答 2查看 799关注 0票数 0

我遇到了一个关于boost beast websocket流的问题。当我尝试写入远程端点已停止响应的流时,该问题会间歇性地发生(特别是由于远程端点与网络的物理连接断开)。

发生此问题时,同步stream.write()调用最终会挂起很长一段时间(分钟),直到套接字最终关闭。我理解这种行为很可能是因为我的程序在没有远程acks的情况下继续写入流,直到发送缓冲区满为止。我想知道是否有一种方法可以将超时应用于写调用,或者是否有一个更类似于stream.try_write()的接口,在那里我可以将错误处理提升到用户级。

我确实意识到一种选择是使用async_write接口。但是,我担心这会将套接字写入操作推迟到io_context的下一次迭代,从而对发送性能产生负面影响。

下面是调用挂起时线程的堆栈跟踪。

代码语言:javascript
复制
#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)
EN

回答 2

Stack Overflow用户

发布于 2018-09-26 11:23:36

Beast websockets不支持非阻塞模式。如果在与websocket流一起使用的套接字上设置此模式,则在某些情况下,websocket::stream的实现将产生未定义的行为。缺少超时是同步代码的一个普遍问题。除了使用异步操作之外,您确实别无选择。您说过要直接从堆栈发送缓冲区,这在异步上下文中通过使用协程很容易实现(请参阅boost::asio::spawnboost::asio::yield_context)。

有许多技术允许异步I/O执行与同步I/O相同或更好的性能,包括在低期望延迟的情况下。

下面是来自Boost.Asio作者关于实现超低延迟的直接建议:https://groups.google.com/a/isocpp.org/d/msg/sg14/FoLFHXqZSck/i4rdO-O3BQAJ

票数 1
EN

Stack Overflow用户

发布于 2018-09-24 21:07:57

我能够通过将底层流套接字设置为非阻塞模式来解决这个问题:

代码语言:javascript
复制
socket.non_blocking(true);

在此模式下,一旦发送缓冲区变满,write()调用将返回boost::system::error_code::try_again (也称为posix EAGAIN)。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52470831

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档