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_RCVTIMEO
和SO_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::read 缓冲区数据大小小于读取大小?