C++ Boost ASIO:如何读取/写入超时?

Posted

技术标签:

【中文标题】C++ Boost ASIO:如何读取/写入超时?【英文标题】:C++ Boost ASIO: how to read/write with a timeout? 【发布时间】:2011-05-31 23:45:34 【问题描述】:

通过阅读其他 Stack Overflow 条目和 boost::asio 文档,我确认没有同步 ASIO 读/写调用也提供易于使用的超时作为调用参数。

我正在使用使用超时的 select(2) 调用转换老式 Linux 套接字应用程序,我需要或多或少地做同样的事情。

那么在boost::asio 中执行此操作的最佳方法是什么?查看 asio 文档,有许多与计时器有关的各种令人困惑的示例,但我很困惑。

我希望看到一个简单易读的示例:从套接字读取,但最多等待 X 秒,之后该函数要么什么都不返回,要么返回任何内容能够在超时到期之前从套接字读取。

【问题讨论】:

您能否详细说明这个示例的混淆之处:think-async.com/Asio/asio-1.4.7/src/examples/timeouts/… - 基本逻辑是,您发送 2 个异步任务,一个是读/写,另一个是超时(如果读/写首先返回你杀死截止时间计时器,如果截止时间计时器返回逻辑是读/写仍然未完成 - 从那里你继续你的超时逻辑。非常非常简单。 在 hf 网络中可能会出现一种与回调队列相关的极端情况。超时 cb 排队,然后读/写排队。当实际上读/写已经完成时,您遇到超时 cb 并开始执行超时逻辑,我见过的一个可能的解决方案类似于双重检查锁定 - 简而言之,当第一个超时返回时执行辅助超时,但是这有同样的问题,如果读/写在第二次超时后排队怎么办... 只要记住超时是一个硬条件,你是说如果我在一定时间内没有得到什么,我会做一些具体的事情 - 这包括读/写的事实可能已经发生并且正在寄给您的路上,但这并不能改变您尚未收到它的事实。 @zenikoder 我认为混淆在于 asio 提供的超时构造使用异步方法强制执行,它们不能与同步方法一起使用。 @Sam:您可以创建同步超时,您只需将异步调用隐藏在阻塞的同步接口后面,直到发生超时或读/写。 【参考方案1】:

这已在 asio 邮件列表中提出,还有一个 ticket 请求该功能。总而言之,如果您需要超时和可取消性,建议使用异步方法。


如果您无法转换为异步方法,您可以尝试SO_RCVTIMEOSO_SNDTIMEO 套接字选项。可以用setsockopt设置,描述符可以用boost::asio::ip::tcp::socket::native方法获取。 man 7 socket 手册页说

SO_RCVTIMEO 和 SO_SNDTIMEO 指定接收或发送超时,直到报告一个 错误。参数是一个结构 时间间隔。如果输入或输出 这一时期的功能块 时间,数据已发送 或收到,该函数的返回值将是 传输的数据量;如果不 数据已被传输并且 已达到超时,然后 -1 是 返回设置为 errno EAGAIN 或 EWOULDBLOCK 就像套接字被指定为 是非阻塞的。如果超时是 设置为零(默认值),然后 操作永远不会超时。 超时仅有效 对于执行套接字 I/O 的系统调用(例如,read(2), recvmsg(2),发送(2),发送消息(2)); 超时对 select(2) 没有影响, poll(2)、epoll_wait(2) 等

【讨论】:

您是否阅读了 CH 对请求的回复? ASIO 在 C++ 中复制 OS 功能,如果您需要某种超时功能,我们非常欢迎您使用 ASIO 提供的 bit-n-pieces 来实现它。【参考方案2】:

我使用了一些asio docs 来制作这个:

class TimeoutAdjust

public:
  TimeoutAdjust(unsigned int dwTimeout) : m_dwTimeout(dwTimeout) ;

  template<class Protocol>
  int level(const Protocol& p) const return SOL_SOCKET;

  template<class Protocol>
  int name(const Protocol& p) const return SO_SNDTIMEO;

  template<class Protocol>
  const void* data(const Protocol& p) const return &m_dwTimeout;

  template<class Protocol>
  size_t size(const Protocol& p) const return sizeof(m_dwTimeout);
private:
  unsigned int m_dwTimeout;
;

用法:

TimeoutAdjust adjust(5000);
sSocket.set_option(adjust);

我调试了它,它似乎做了它应该做的事情。

【讨论】:

我在这里读到的是SO_SNDTIMEO 采用timeval,而不是unsigned int。 linux.die.net/man/7/socket 啊,MS 文档使用 DWORD 表示 SO_SNDTIMEO。看起来 timeval 是一对长整数,所以读者要小心。微软文档:msdn.microsoft.com/en-ca/library/windows/desktop/… 使用上述代码后,我得到一个异常异常:set_option:无效参数。如果您有一些参考代码,请分享相同的。

以上是关于C++ Boost ASIO:如何读取/写入超时?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 boost asio 中设置阻塞套接字的超时时间?

C++ Boost asio 连接和流式传输

为啥 boost::asio::read 缓冲区数据大小小于读取大小?

boost::async 读写在一次读取和两次写入后卡住

多线程应用程序上的 boost::asio::ssl 访问冲突

使用 Boost Asio 在 TCP 套接字上执行异步写入操作