Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 带超时的Boost ASIO异步套接字_Sockets_Boost_Timeout_Asio - Fatal编程技术网

Sockets 带超时的Boost ASIO异步套接字

Sockets 带超时的Boost ASIO异步套接字,sockets,boost,timeout,asio,Sockets,Boost,Timeout,Asio,我正试图找到合适的/规范的方法来实现下面的代码,该代码围绕异步asio方法提供了一个同步包装器,以便有一个超时。代码似乎可以工作,但我所看到的示例中没有一个使用lambda中的布尔值来终止运行I/o服务的do/while循环,因此我不确定这是否是正确的形式,或者它是否会产生意想不到的后果。有些人会这样做 while(IOService.run_one); 但这永远不会结束 编辑: 我试图遵循以下示例: 但在这段代码中,它们避免了使用终止符读取的字节数。我需要读取的字节数,因此需要回调 我见过许

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

编辑: 我试图遵循以下示例:

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

我见过许多其他使用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;
}

我就是这样做的。触发的第一个事件导致
io\u 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;
}

阅读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;
}

如果您希望它与超时同步,那么为什么要使用异步I/O呢?据我所知,这是使用带超时的boost asio的首选/唯一方法。从理论上讲,您可以获得本机套接字和setsockopt,但从我所读到的内容来看,它显然既不推荐,也不可靠,也不可移植。似乎首选的机制是使用boost::use_future,但这是gcc 5.4.0/boost 1.58上没有编译的,我不是这样使用超时的。在调用asyncëu receive时设置截止日期,在收到数据包时重置截止日期。Michaël Roy-我不确定你的确切意思。据我所知,我对超时机制没有任何问题——我直接从boost示例中获得了它。米夏埃尔·罗伊——谢谢——我会试试看。它看起来比我偶然发现的要好。我相信它是有效的,但我明天一确认就会把它标记为答案。@olympionex考虑到这一点,还有另一种选择:直接设置套接字的超时选项。Michaël Roy-我一开始读过这篇文章,但这篇详细的文章似乎强烈建议不要这样做:Michaël Roy-当我运行您发布的代码时,它目前只是挂在ioëu service::run()中。根据文档:he run()函数会一直阻塞,直到所有工作都完成并且不再需要分派处理程序,或者直到io_服务停止。我不知道还有什么其他出色的工作要做,但我必须做更多的调试,看看是怎么回事。我之前尝试过run(),结果也是一样的,这就是为什么我使用布尔值来终止循环调用run\u一次。我还尝试过在async\u receive调用之前调用io\u service::reset(),正如文档所述:必须在第二次或以后的run()调用集、run\u one()调用集、poll()调用之前调用此函数或poll_one()函数,当由于io_服务停止或工作不足而返回这些函数的上一次调用时。调用reset()后,io_服务对象的stopped()函数将返回false。当对run()、run_one()、poll()或poll_one()函数有任何未完成的调用时,不得调用此函数。