vico
vico

Reputation: 18171

Setting timeout to recv function

I read from socket using recv function. I have problem when no data available for reading. My programm just stops. I found that I can set timeout using select function. But looks that timeout affects select function itself and recv that goes after select still waits uncontinuously.

fd_set set;
struct timeval timeout;
FD_ZERO(&set); /* clear the set */
FD_SET(s, &set); /* add our file descriptor to the set */
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC;
timeout.tv_usec = 0;
int rv = select(s, &set, NULL, NULL, &timeout);
if((recv_size = recv(s , rx_tmp , bufSize ,0)) == SOCKET_ERROR)
      {
      ...
      }

How to ask recv function return after some timout?

Upvotes: 18

Views: 54900

Answers (3)

Nemanja Boric
Nemanja Boric

Reputation: 22157

You should check return value of select. select will return 0 in case timeout expired, so you should check for error and call recv only if select returned positive value:

On success, select() and pselect() return the number of file descriptors contained in the three returned descriptor sets (that is, the total number of bits that are set in readfds, writefds, exceptfds) which may be zero if the timeout expires before anything interesting happens.

int rv = select(s + 1, &set, NULL, NULL, &timeout);
if (rv == SOCKET_ERROR)
{
    // select error...
}
else if (rv == 0)
{
    // timeout, socket does not have anything to read
}
else
{
    // socket has something to read
    recv_size = recv(s, rx_tmp, bufSize, 0);
    if (recv_size == SOCKET_ERROR)
    {
        // read failed...
    }
    else if (recv_size == 0)
    {
        // peer disconnected...
    }
    else
    {
        // read successful...
    }
}

Upvotes: 14

Remy Lebeau
Remy Lebeau

Reputation: 596387

Another way to set a timeout on recv() itself without using select() is to use setsockopt() to set the socket's SO_RCVTIMEO option (on platforms that support it).

On Windows, the code would look like this:

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

//...

recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == SOCKET_ERROR)
{
    if (WSAGetLastError() != WSAETIMEDOUT)
        //...
}

On other platforms, the code would look like this instead:

struct timeval timeout;
timeout.tv_sec = SOCKET_READ_TIMEOUT_SEC;
timeout.tv_usec = 0;
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

//...

recv_size = recv(s, rx_tmp, bufSize, 0);
if (recv_size == -1)
{
    if ((errno != EAGAIN) && (errno != EWOULDBLOCK))
        //...
}

Upvotes: 37

Richard Hodges
Richard Hodges

Reputation: 69892

use the FD_ISSET() macro to test whether there is data to read. If it returns false, don't do the read.

http://linux.die.net/man/3/fd_set

Upvotes: 1

Related Questions