关闭后提升 asio async_connect 成功

tob*_*oby 1 c++ sockets boost boost-asio

单线程应用程序。

它不是每次都发生,只有在高负载 1.5 小时后才会发生。

  1. tcp::socket::async_connect
  2. tcp::socket::close(通过deadline_timer)
  3. async_connect_handler 给出成功 error_code (一百万次之一),但套接字被(2)关闭。99.999% 的时间它给出 errno=125 (ECANCELED)。

套接字实现或 boost asio 是否有可能以某种方式执行此操作:

  1. 异步连接
  2. 异步成功发布到 io_service
  3. 定时关闭
  4. 异步成功由我处理,不受关闭影响

现在通过在我的变量中保存状态来解决,忽略接受成功。

Linux 2.6 (fedora)。提升 1.46.0

PS:当然可能有我的错误......但如果不是这样的话,它可以顺利运行几天。

Tan*_*ury 5

正如 Igor 在评论中提到的,完成处理程序已经排队。

这种情况是操作执行时间和处理程序被调用时间间隔的结果。对于文档io_service::run()io_service::run_one()io_service::poll(),和io_service::poll_one()特定提处理,而不是操作。在场景中,socket::async_connect()操作和deadline_timer::async_wait()操作在同一个事件循环迭代中完成。这导致两个处理程序都以io_service未指定的顺序添加到延迟调用中。

考虑以下突出场景的片段:

void handle_wait(const boost::system::error_code& error)
{
  if (error) return;
  socket_.close();
}

timer_.expires_from_now(boost::posix_time::seconds(30));
timer_.async_wait(&handle_wait);
socket_.async_connect(endpoint_, handle_connect);
boost::this_thread::sleep(boost::posix_time::seconds(60));
io_service_.run_one();
Run Code Online (Sandbox Code Playgroud)

io_service_.run_one()被调用时,socket::async_connect()deadline_timer::async_wait()操作可能已经完成,导致handle_waithandle_connect准备好以io_service未指定的顺序从内部调用。为了正确处理这个未指定的顺序,需要从内部发生额外的逻辑handle_wait()handle_connect()查询当前状态,并确定其他处理程序是否已被调用,而不是仅依赖于操作的状态 ( error_code)。

确定其他处理程序是否已调用的最简单方法是:

  • handle_connect(),检查套接字是否仍然打开通过is_open()。如果套接字仍然打开,则handle_timer()尚未调用。一个干净的方式来指示handle_timer()handle_connect()具有RAN是更新到期时间。
  • 在 中handle_timer(),检查是否已过期。如果这是真的,那么handle_connect()还没有跑,所以关闭套接字。

生成的处理程序可能如下所示:

void handle_wait(const boost::system::error_code& error)
{
  // On error, return early.
  if (error) return;

  // If the timer expires in the future, then connect handler must have
  // first.
  if (timer_.expires_at() > deadline_timer::traits_type::now()) return;

  // Timeout has occurred, so close the socket.
  socket_.close();
}

void handle_connect(const boost::system::error_code& error)
{
  // The async_connect() function automatically opens the socket at the start
  // of the asynchronous operation. If the socket is closed at this time then
  // the timeout handler must have run first.
  if (!socket_.is_open()) return;

  // On error, return early.
  if (error) return;

  // Otherwise, a connection has been established.  Update the timer state
  // so that the timeout handler does not close the socket.
  timer_.expires_at(boost::posix_time::pos_infin);
}
Run Code Online (Sandbox Code Playgroud)

Boost.Asio 提供了一些处理超时的示例