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

有没有办法取消挂起的操作(没有断开连接)或设置增强库函数的超时?

即我想设置一个阻塞套接字在升压ASIO超时?

socket.read_some(boost :: asio :: buffer(pData,maxSize),error_);

例如:我想从套接字中读取一些信息,但是如果10秒钟过去了,我想抛出一个错误。

在Linux / BSD下,操作系统直接支持套接字上I / O操作的超时。 该选项可以通过setsocktopt()来启用。 我不知道如果boost::asio提供了一个方法来设置它或暴露套接字scriptor让你直接设置它 – 后一种情况是不是真正的便携式。

为了完整起见,这里是手册页的描述:

SO_RCVTIMEOSO_SNDTIMEO

  Specify the receiving or sending timeouts until reporting an error. The argument is a struct timeval. If an input or output function blocks for this period of time, and data has been sent or received, the return value of that function will be the amount of data transferred; if no data has been transferred and the timeout has been reached then -1 is returned with errno set to EAGAIN or EWOULDBLOCK just as if the socket was specified to be non-blocking. If the timeout is set to zero (the default) then the operation will never timeout. Timeouts only have effect for system calls that perform socket I/O (eg, read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for select(2), poll(2), epoll_wait(2), etc. 

当问这个问题时,我想ASIO没有任何例子来说明如何完成OP所需要的,也就是超时阻塞操作,例如阻塞套接字操作。 现在有一些例子可以告诉你如何做到这一点。 这个例子似乎很长,但那是因为这是好评。 它显示了如何在“一次性”模式下使用ioservice。

我认为这个例子是一个很好的解决scheme。 这里的其他解决scheme打破了可移植性,并没有利用ioservice。 如果可移植性不重要,而ioservice似乎要花费太多的开销–THEN–你不应该使用ASIO。 无论如何,你将会创build一个ioservice(几乎所有的ASIOfunction都依赖于它,甚至同步套接字),所以充分利用它。

超时阻塞asio tcp操作

超时阻止asio udp操作

ASIO文档已经更新了,所以请看看如何克服ASIO使用的一些“陷阱”的新例子。

你可以做一个async_read,并为你想要的时间设置一个计时器。 然后,如果定时器触发,请在您的套接字对象上调用cancel。 否则,如果你的阅读发生,你可以取消你的计时器。 这需要你使用一个io_service对象当然。

编辑:find一个代码片段,你这样做

http://lists.boost.org/Archives/boost/2007/04/120339.php

我有同样的问题,并经过一番研究,我可以想出最简单,最干净的解决scheme是获得底层本地套接字,并做一个select,直到有数据要读取。 select将采取超时参数。 当然,使用本地套接字开始反对使用asio的地步,但是,这似乎是最干净的方式。 据我所知,asio没有提供一种轻松实现同步使用的方法。 码:

  // socket here is: boost::shared_ptr<boost::asio::ip::tcp::socket> a_socket_ptr // Set up a timed select call, so we can handle timeout cases. fd_set fileDescriptorSet; struct timeval timeStruct; // set the timeout to 30 seconds timeStruct.tv_sec = 30; timeStruct.tv_usec = 0; FD_ZERO(&fileDescriptorSet); // We'll need to get the underlying native socket for this select call, in order // to add a simple timeout on the read: int nativeSocket = a_socket_ptr->native(); FD_SET(nativeSocket,&fileDescriptorSet); select(nativeSocket+1,&fileDescriptorSet,NULL,NULL,&timeStruct); if(!FD_ISSET(nativeSocket,&fileDescriptorSet)){ // timeout std::string sMsg("TIMEOUT on read client data. Client IP: "); sMsg.append(a_socket_ptr->remote_endpoint().address().to_string()); throw MyException(sMsg); } // now we know there's something to read, so read boost::system::error_code error; size_t iBytesRead = a_socket_ptr->read_some(boost::asio::buffer(myVector), error); ... 

也许这会对你的情况有用。

接下来是什么grepsedawk已经提到。 有几个示例显示如何在asio doco中的Timeouts部分下,在一段时间之后取消长时间运行的asynchronous操作。 提升Asio的例子 。 asynchronousTCP客户端帮助了我最多。

快乐异己:)

在原来的问题甚至几年之后,仍然没有令人满意的答案。

手动使用select不是一个好的select

  1. 文件描述符编号必须小于1024
  2. 由于校验和错误,FD可能被虚假地报告为准备就绪。

调用io_service.run_one()也是一个坏主意,因为可能有其他的asynchronous选项需要一个io_service来始终run() 。 而boost的关于阻塞tcp客户端的文档很难理解。

所以这是我的解决scheme。 关键的想法如下:

 { Semaphore r_sem; boost::system::error_code r_ec; boost::asio::async_read(s,buffer, [this, &r_ec, &r_sem](const boost::system::error_code& ec_, size_t) { r_ec=ec_; r_sem.notify(); }); if(!r_sem.wait_for(std::chrono::seconds(3))) // wait for 3 seconds { s.cancel(); throw boost::system::system_error(boost::asio::error::try_again); } else if(r_ec) throw boost::system::system_error(r_ec); } 

这里的Semaphore只是一个互斥和一个condition_variable。
wait_forhttp://en.cppreference.com/w/cpp/thread/condition_variable/wait_for

完整的代码在https://github.com/scinart/cpplib/blob/master/include/asio.hpp
例子在https://github.com/scinart/cpplib/blob/master/test/test_asio.cpp
更好的例子在https://github.com/scinart/cpplib/blob/master/test/test_SyncBoostIO.cpp

您可以将同步调用包装到期货中,并等待它完成并有一个超时(wait_timeout)。

http://www.boost.org/doc/libs/1_47_0/doc/html/thread/synchronization.html#thread.synchronization.futures

当然,不是一个大小适合所有,但适用于例如绕过缓慢的连接超时。

在* nix上,你可以使用alarm(),这样你的套接字调用将会失败,EINTR