【问题标题】:Boost ASIO asynchronous socket with timeoutBoost ASIO 异步套接字超时
【发布时间】:2017-06-16 09:05:05
【问题描述】:

我正在尝试找到正确/规范的方法来实现下面的代码,该代码提供了一个围绕异步 asio 方法的同步包装器,以实现超时。代码似乎可以工作,但我看过的示例都没有使用 lambda 中的布尔值来终止运行 i/o 服务的 do/while 循环,所以我不确定这是否是正确的形式,或者它是否会有意想不到的后果。有些人会做类似的事情 而(IOService.run_one); 但这永远不会终止。

编辑: 我正在尝试遵循此示例: http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/timeouts/blocking_tcp_client.cpp

但在这段代码中,它们避免了使用 \n 终止符读取的字节数。我需要读取的字节数,因此需要回调。

我见过许多其他使用 boost async futures 以及其他方法的解决方案,但它们似乎无法与 Ubuntu 16.04 的 gcc / boost 标准版本一起编译,我想继续使用这些版本。

ByteArray SessionInfo::Read(const boost::posix_time::time_duration &timeout)
{

  Deadline.expires_from_now(timeout);
  auto bytes_received = 0lu;
  auto got_callback = false;

  SessionSocket->async_receive(boost::asio::buffer(receive_buffer_,
                               1024),
                               [&bytes_received, &got_callback](const boost::system::error_code &error, std::size_t bytes_transferred) {
                             bytes_received = bytes_transferred;
                             got_callback = true;
                           });
  do
  {
    IOService.run_one();
  }while (!got_callback);

  auto bytes = ByteArray(receive_buffer_, receive_buffer_ + bytes_received);
  return bytes;
}

【问题讨论】:

  • 如果你希望它与超时同步,你为什么要使用异步 I/O?
  • 据我了解,这是在超时的情况下使用 boost asio 的首选/唯一方法。从理论上讲,您可以获得本机套接字和 setsockopt,但从我阅读的内容来看,它显然既不推荐、也不可靠或可移植。似乎首选机制是使用 boost::use_future,但那是在 gcc 5.4.0 / boost 1.58 上无法编译的
  • 这不是我使用超时的方式。在调用 async_receive 时设置截止日期,并在收到数据包时重新设置。
  • Michaël Roy - 我不确定你的意思。据我所知,我没有遇到超时机制的问题 - 我直接从 boost 示例中得到它。

标签: sockets boost timeout asio


【解决方案1】:

我就是这样做的。触发的第一个事件会导致 io_service::run() 返回。

ByteArray SessionInfo::Read(const boost::posix_time::time_duration &timeout)
{
  Deadline.expires_from_now(timeout);  // I assume this is a member of SessionInfo
  auto got_callback{false};
  auto result = ByteArray();

  SessionSocket->async_receive(  // idem for SessionSocket
    boost::asio::buffer(receive_buffer_, 1024),
    [&](const boost::system::error_code error, 
        std::size_t bytes_received) 
    {
      if (!ec)
      {
        result = ByteArray(receive_buffer_, bytes_received);
        got_callback = true;
      }
      Deadline.cancel();
    });

  Deadline.async_wait([&](const boost::system::error_code ec) 
  {
     if (!ec)
     {
       SessionSocket->cancel();
     }
  });        

  IOService.run();

  return result;
}

【讨论】:

  • Michaël Roy - 谢谢 - 我会试一试。它看起来比我偶然发现的要好。我相信它有效,但我会在明天确认后立即将其标记为答案。
  • @olympionex 想了想,也有这样的选择:直接设置socket的超时选项。 stackoverflow.com/questions/292997/…
  • Michaël Roy - 我最初读到过这个,但这篇详细的帖子似乎强烈反对它:stackoverflow.com/a/30428941/3708683
  • Michaël Roy - 当我运行您发布的代码时,它目前只是挂在 io_service::run() 中。根据文档:他 run() 函数阻塞,直到所有工作完成并且没有更多的处理程序要分派,或者直到 io_service 已停止。我不知道还有什么其他出色的工作正在完成,但我必须做更多的调试才能看到发生了什么。我之前尝试过 run() 得到相同的结果,这就是为什么我使用布尔值来终止调用 run_once 的循环。
  • 我还尝试在 async_receive 调用之前调用 io_service::reset(),如文档所述:此函数必须在 run()、run_one() 的任何第二个或以后的调用集之前调用, poll() 或 poll_one() 函数,当这些函数的先前调用由于 io_service 停止或耗尽工作而返回时。调用reset() 后,io_service 对象的stopped() 函数将返回false。当对 run()、run_one()、poll() 或 poll_one() 函数有任何未完成的调用时,不得调用此函数。
【解决方案2】:

阅读 M. Roy 回答下方的对话,您的目标是确保 IOService.run(); 返回。所有点都是有效的,boost::asio::io_service 的实例在每个执行线程中只能运行一次(意味着不能同时运行,但可以连续运行多次),因此必须知道它是如何使用的。也就是说,为了使IOService 停止,我将修改 M. Roy 的解决方案,如下所示:

ByteArray SessionInfo::Read(const boost::posix_time::time_duration &timeout) {
  Deadline.expires_from_now(timeout);
  auto got_callback{false};
  auto result = ByteArray();

  SessionSocket->async_receive(
      boost::asio::buffer(receive_buffer_, 1024),
      [&](const boost::system::error_code error, 
          std::size_t bytes_received)  {
        if (!ec) {
          result = ByteArray(receive_buffer_, bytes_received);
          got_callback = true;
        }
        Deadline.cancel();
      });

  Deadline.async_wait(
      [&](const boost::system::error_code ec) {
        if (!ec) {
          SessionSocket->cancel();
          IOService.stop();
        }
      });        

  IOService.run();
  return result;
}

【讨论】:

    猜你喜欢
    • 2011-12-05
    • 1970-01-01
    • 2016-03-05
    • 1970-01-01
    • 2011-10-15
    • 1970-01-01
    • 2016-06-19
    • 1970-01-01
    相关资源
    最近更新 更多