24

From reading other Stack Overflow entries and the boost::asio documentation, I've confirmed that there is no synchronous ASIO read/write calls that also provide an easy-to-use timeout as a parameter to the call.

I'm in the middle of converting an old-school Linux socket application with select(2) calls that employs timeouts, and I need to do more-or-less the same.

So what is the best way to do this in boost::asio? Looking at the asio documentation, there are many confusing examples of various things to do with timers, but I'm quite confused.

I'd love to see a simple-to-read example of this: Read from a socket, but wait for a maximum of X seconds after which the function either returns with nothing, or returns with whatever it was able to read from the socket before the timeout expired.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Stéphane
  • 19,459
  • 24
  • 95
  • 136
  • 4
    Can you please elaborate what is confusing about this example: http://think-async.com/Asio/asio-1.4.7/src/examples/timeouts/blocking_tcp_client.cpp - The essential logic is, you despatch 2 async tasks, one a read/write and the other a time-out if the read/write returns first you kill the deadline timer, if the deadline timer returns the logic is the read/write is still outstanding - from there you proceed with your time-out logic. very very simple. –  Dec 29 '10 at 18:02
  • 2
    There is one corner case that might arise in hf networking that is related to the queuing of the callbacks. the timeout cb is queued, then the read/write is queued. you encounter the timeout cb and begin to execute time-out logic when in reality the read/write had completed, a possible solution i've seen is something similar to double check lock - in short perform a secondary timeout when the first timeout returns, but then this has the same problem what if the read/write is queued after the 2nd timeout is queue... –  Dec 29 '10 at 18:08
  • 2
    Just remember a timeout is a hard condition, you're saying if i don't get something in a certain amount of time, i will do something specific - this includes the fact that the read/write may have alreadyoccured and is on its way to you, that doesn't change the fact that you haven't recieved it as of yet. –  Dec 29 '10 at 18:10
  • 2
    @zenikoder I believe the confusion is that the timeout constructs provided by asio enforce using the asynchronous methods, they cannot be used with synchronous methods. – Sam Miller Dec 29 '10 at 18:59
  • 1
    @Sam: you can create a synchronous timeout, you just hide an asynch call behind a synchrouch interface that blocks, until either a timeout or a read/write occurs. –  Dec 29 '10 at 20:54
  • One possible solution for READ, would be to call socket.available() to determine the number of bytes available for reading, and invoke read_some with that exact (or less, never more) amount. The call shall not block and you can enforce a timeout around that. – pbn Sep 08 '22 at 07:43

2 Answers2

7

This has been brought up on the asio mailing lists, there's a ticket requesting the feature as well. To summarize, it is suggested to use asynchronous methods if you desire timeouts and cancellability.


If you cannot convert to asynchronous methods, you might try the SO_RCVTIMEO and SO_SNDTIMEO socket options. They can be set with setsockopt, the descriptor can be obtained with the boost::asio::ip::tcp::socket::native method. The man 7 socket man page says

SO_RCVTIMEO and SO_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 (e.g., read(2), recvmsg(2), send(2), sendmsg(2)); timeouts have no effect for select(2), poll(2), epoll_wait(2), etc.

Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • 1
    Did you read CH's response to the request? ASIO replicates OS functionality in C++, if you requrie some kind of time-out functionality, you're more than welcome to implement it using the bit-n-pieces ASIO provides. –  Dec 29 '10 at 18:04
6

I used some asio docs to produce this:

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

Usage:

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

I debugged it, and it appears to do what it is supposed to.

ArtHare
  • 1,798
  • 20
  • 22
  • 2
    What I read here is that `SO_SNDTIMEO` takes a `timeval`, rather than an `unsigned int`. http://linux.die.net/man/7/socket – updogliu Jul 14 '14 at 23:16
  • Ah, the MS docs use a DWORD for SO_SNDTIMEO. Looks like timeval is a pair of long ints, so reader beware. MS docs: http://msdn.microsoft.com/en-ca/library/windows/desktop/ms740532(v=vs.85).aspx – ArtHare Jul 15 '14 at 02:57
  • 2
    After using above code i am getting an exception Exception: set_option: Invalid argument.If you have some reference code then please share the same. – asim Sep 12 '14 at 17:48