关闭后提升asio async_connect成功率

时间:2013-01-29 15:44:00

标签: c++ sockets boost boost-asio

单线程应用程序。

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

  1. TCP ::插座:: async_connect
  2. tcp :: socket :: close(by deadline_timer)
  3. async_connect_handler给出成功error_code(一百万次之一),但socket被(2)关闭。 99.999%的时间给出errno = 125(ECANCELED)。
  4. 套接字实现或提升asio是否可能以某种方式执行此操作:

    1. async_connect
    2. 异步成功发布到io_service
    3. 关闭计时器
    4. 异步成功由我处理,不受关闭
    5. 的影响

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

      Linux 2.6(fedora)。 提升1.46.0

      PS:对我而言可能存在错误...但如果不是这样的话,可以顺利运行几天。

2 个答案:

答案 0 :(得分:4)

正如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();

调用io_service_.run_one()时,socket::async_connect()deadline_timer::async_wait()操作可能都已完成,导致handle_waithandle_connect准备好从io_service内调用{1}}以未指定的顺序排列。要正确处理此未指定的顺序,需要在handle_wait()handle_connect()内进行额外的逻辑以查询当前状态,并确定是否已调用其他处理程序,而不是仅仅依赖于状态({ {1}})操作。

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

  • error_code中,通过is_open()检查套接字是否仍处于打开状态。如果套接字仍处于打开状态,则尚未调用handle_connect()。向handle_timer()表明handle_timer()已运行的干净方法是更新到期时间。
  • handle_connect()中,检查过期时间是否已过。如果这是真的,那么handle_timer()没有运行,所以关闭套接字。

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

handle_connect()

Boost.Asio为处理超时提供了一些examples

答案 1 :(得分:0)

我接受twsansbury的回答,只想添加更多信息。

关于shutdown():

void async_recv_handler( boost::system::error_code ec_recv, std::size_t count )
{
    if ( !m_socket.is_open() )
        return; // first time don't trust to ec_recv
    if ( ec_recv )
    {
        // oops, we have error
        // log
        // close
        return;
    }
    // seems that we are just fine, no error in ec_recv, we can gracefully shutdown the connection
    // but shutdown may fail! this check is working for me
    boost::system::error_code ec_shutdown;
    // second time don't trusting to ec_recv
    m_socket.shutdown( t, ec_shutdown );
    if ( !ec_shutdown )
        return;
    // this error code is expected
    if ( ec_shutdown == boost::asio::error::not_connected )
       return;
    // other error codes are unexpected for me
    // log << ec_shutdown.message()
    throw boost::system::system_error(ec_shutdown);
}