Sockets 带超时的Boost ASIO异步套接字
我正试图找到合适的/规范的方法来实现下面的代码,该代码围绕异步asio方法提供了一个同步包装器,以便有一个超时。代码似乎可以工作,但我所看到的示例中没有一个使用lambda中的布尔值来终止运行I/o服务的do/while循环,因此我不确定这是否是正确的形式,或者它是否会产生意想不到的后果。有些人会这样做 while(IOService.run_one); 但这永远不会结束 编辑: 我试图遵循以下示例: 但在这段代码中,它们避免了使用终止符读取的字节数。我需要读取的字节数,因此需要回调 我见过许多其他使用boost async futures和其他方法的解决方案,但它们似乎没有使用适用于Ubuntu 16.04的gcc/boost标准版本进行编译,我希望继续使用这些版本Sockets 带超时的Boost ASIO异步套接字,sockets,boost,timeout,asio,Sockets,Boost,Timeout,Asio,我正试图找到合适的/规范的方法来实现下面的代码,该代码围绕异步asio方法提供了一个同步包装器,以便有一个超时。代码似乎可以工作,但我所看到的示例中没有一个使用lambda中的布尔值来终止运行I/o服务的do/while循环,因此我不确定这是否是正确的形式,或者它是否会产生意想不到的后果。有些人会这样做 while(IOService.run_one); 但这永远不会结束 编辑: 我试图遵循以下示例: 但在这段代码中,它们避免了使用终止符读取的字节数。我需要读取的字节数,因此需要回调 我见过许
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()函数有任何未完成的调用时,不得调用此函数。