132

How can I try to read data from socket with timeout? I know, select, pselect, poll, has a timeout field, but using of them disables "tcp fast-path" in tcp reno stack.

The only idea I have is to use recv(fd, ..., MSG_DONTWAIT) in a loop

red0ct
  • 4,840
  • 3
  • 17
  • 44
osgx
  • 90,338
  • 53
  • 357
  • 513

5 Answers5

239

You can use the setsockopt function to set a timeout on receive operations:

SO_RCVTIMEO

Sets the timeout value that specifies the maximum amount of time an input function waits until it completes. It accepts a timeval structure with the number of seconds and microseconds specifying the limit on how long to wait for an input operation to complete. If a receive operation has blocked for this much time without receiving additional data, it shall return with a partial count or errno set to [EAGAIN] or [EWOULDBLOCK] if no data is received. The default for this option is zero, which indicates that a receive operation shall not time out. This option takes a timeval structure. Note that not all implementations allow this option to be set.

// LINUX
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

// WINDOWS
DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);

// MAC OS X (identical to Linux)
struct timeval tv;
tv.tv_sec = timeout_in_seconds;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);

Reportedly on Windows this should be done before calling bind. I have verified by experiment that it can be done either before or after bind on Linux and OS X.

Quuxplusone
  • 23,928
  • 8
  • 94
  • 159
Robert S. Barnes
  • 39,711
  • 30
  • 131
  • 179
  • 7
    This answer saved my ass. I was stuck implementing that convoluted "select" crap, with no success. This worked immediately, so much simpler. – MiloDC Nov 16 '17 at 21:06
  • Now that is why timeout on windows is not working because I am using the code for linux. Thanks. If windows is not using `struct timeval tv;` then does it mean select() wont work too? I tried porting my select() code to windows and it just timeouts immediately it looks like its ignoring the value I am setting at timeval. – kuchi Dec 10 '17 at 19:34
  • 1
    I set timeout value to 5 secs. Why does it always take 5 seconds for each reading cycle regardless there is incoming data or not? – Han Feb 26 '18 at 12:57
  • 2
    this also works on windows even after bind operation. tried on windows 10 – cahit beyaz Apr 04 '18 at 06:07
  • can this result in loosing udp packages, eg when the timeout just kicks in when a new message is received? – 463035818_is_not_an_ai Apr 11 '18 at 12:43
  • 2
    @user463035818 [This answer](https://stackoverflow.com/a/49776408/1910445) claims it shouldn't. – Tomeamis Apr 14 '18 at 15:08
28

Here's some simple code to add a time out to your recv function using poll in C:

struct pollfd fd;
int ret;

fd.fd = mySocket; // your socket handler 
fd.events = POLLIN;
ret = poll(&fd, 1, 1000); // 1 second for timeout
switch (ret) {
    case -1:
        // Error
        break;
    case 0:
        // Timeout 
        break;
    default:
        recv(mySocket,buf,sizeof(buf), 0); // get your data
        break;
}
Kevin
  • 16,549
  • 8
  • 60
  • 74
Abdessamad Doughri
  • 1,324
  • 2
  • 16
  • 29
  • this would not work exactly as expected. `poll` will wait for receiving at least one byte or timeout, whereas when calling the `recv` function it will wait for `sizeof(buf)` bytes, causing it to block again if this count has not yet arrived, but this time without having a timeout. – LoPiTaL Jun 23 '20 at 07:59
  • 3
    Looking at and , `recv` should return any amount of data available up to `sizeof(buf)` bytes. So this solution should be fine. – GILGAMESH Jan 01 '21 at 23:11
2

// works also after bind operation for WINDOWS

DWORD timeout = timeout_in_seconds * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof timeout);
cahit beyaz
  • 4,829
  • 1
  • 30
  • 25
1

Install a handler for SIGALRM, then use alarm() or ualarm() before a regular blocking recv(). If the alarm goes off, the recv() will return an error with errno set to EINTR.

caf
  • 233,326
  • 40
  • 323
  • 462
-3

LINUX

struct timeval tv;
tv.tv_sec = 30;        // 30 Secs Timeout
tv.tv_usec = 0;        // Not init'ing this can cause strange errors
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));

WINDOWS

DWORD timeout = SOCKET_READ_TIMEOUT_SEC * 1000;
setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));

NOTE: You have put this setting before bind() function call for proper run

Arpit
  • 6,212
  • 8
  • 38
  • 69
vivek
  • 101
  • 1
  • 2