c++ - deadline_timer 只等待一次

标签 c++ sockets boost boost-asio

我已经为 boost::asio 实现了一个非常标准的阻塞 api 模拟和超时。这是我的主要周期:

io_service io_svc;
tcp::endpoint endpoint(tcp::v4(), m_port);
tcp::acceptor acceptor(io_svc, endpoint);

accept_helper acc_hlpr(acceptor, 5000);

while (m_bStop == false)
{
  tcp::socket socket(io_svc);

  if (acc_hlpr.accept(socket))
  {
    // do stuff

    socket.close();
  }
}


这是辅助类

class accept_helper
{
public:
  accept_helper (tcp::acceptor &acc, size_t msTO) : m_timer(acc.get_io_service()), m_acceptor(acc), m_msTO(msTO) { }

  bool accept (tcp::socket &socket)
  {
    m_bTimeout = false;
    m_bAccept = false;

    m_timer.expires_from_now(boost::posix_time::milliseconds(m_msTO));
    m_timer.async_wait(boost::bind(&accept_helper::handle_timeout, this, boost::asio::placeholders::error));

    m_acceptor.async_accept(socket, boost::bind(&accept_helper::handle_accept, this));  

    m_timer.get_io_service().run_one();
    m_timer.get_io_service().reset();

    if (m_bAccept)
    {
      m_timer.cancel();
      return true;
    }
    else if (m_bTimeout)
    {
      // BOOST_ASIO_ENABLE_CANCELIO is defined
      boost::system::error_code ec;
      m_acceptor.cancel(ec);
    }

    return false;
  }

private:
  void          handle_accept (void)
  {
    boost::mutex::scoped_lock lock(m_mutex);
    m_bAccept = true;
  }

  void          handle_timeout(const boost::system::error_code & error)
  {
    if (!error)
    {
      boost::mutex::scoped_lock lock(m_mutex);
      m_bTimeout = true;
    }
  }

private:
  boost::asio::deadline_timer m_timer;
  boost::asio::ip::tcp::acceptor &m_acceptor;
  boost::mutex m_mutex;
  size_t m_msTO;
  bool m_bTimeout;
  bool m_bAccept;
};

问题是计时器只在第一次迭代时等待。在其他人身上,run_one 方法只是立即返回并且没有设置任何标志。我曾尝试将计时器设置为本地计时器,但这没有帮助。如何让定时器每次都等待?

固定版本

bool accept (tcp::socket &socket)
  {
    m_bTimeout = false;
    m_bAccept = false;

    m_timer.expires_from_now(boost::posix_time::milliseconds(m_msTO));
    m_timer.async_wait(boost::bind(&accept_helper::handle_timeout, this, boost::asio::placeholders::error));

    m_acceptor.async_accept(socket, boost::bind(&accept_helper::handle_accept, this, boost::asio::placeholders::error));    

    m_timer.get_io_service().reset();
    m_timer.get_io_service().run_one();

    if (m_bAccept)
    {
      m_timer.cancel();
    }
    else if (m_bTimeout)
    {
      boost::system::error_code ec;
      m_acceptor.cancel(ec);
    }

    while (m_timer.get_io_service().run_one());

    return m_bAccept;
  }

private:
  void          handle_accept (const boost::system::error_code & error)
  {
    if (!error)
    {
      boost::mutex::scoped_lock lock(m_mutex);
      m_bAccept = true;
    }
  }

  void          handle_timeout(const boost::system::error_code & error)
  {
    if (!error)
    {
      boost::mutex::scoped_lock lock(m_mutex);
      m_bTimeout = true;
    }
  }

最佳答案

io_service::reset()函数只允许 io_service 从停止状态恢复运行;它不会删除任何已经排队到 io_service 中的处理程序。在这种情况下,在 io_service 上启动了两个操作(async_waitasync_accept),但只执行了一个处理程序,因为 io_service 的事件循环正在由 io_service::run_one() 处理.在下一次调用 accept_helper::accept() 时,将执行上一次调用的处理程序。

要解决此问题,请考虑运行 io_service 直到两个处理程序都已被调用。一些解决方案将运行 io_service 直至完成,如 answer 所示。和 Boost.Asio blocking tcp client timeout example .

关于c++ - deadline_timer 只等待一次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17307098/

相关文章:

c++ - C++如何为类成员函数分配内存?

java - 是否可以在 Java 中编辑支持的密码套件列表

c++ - boost shared_ptr vector 成员访问

c++ - 从网络队列中读取多个数据报

c++ - 编写更通用的指针代码

c++ - 在 C++ 中为动态分配的类型重载 + 运算符

c++ - 从 vector 中最快删除元素或更好地使用内存(排序基数)

c++ - 如何检查套接字在一段时间内没有接收

javascript - io.emit 与 socket.emit

c++ - 使用 boost 序列化从 XML 加载类