Установка тайм-аута для функции recv

Я читаю из сокета с помощью

3 ответов


вы должны проверить возвращаемое значение select. select вернутся 0 в случае истечения тайм-аута, поэтому вы должны проверить ошибку и вызвать recv только если select возвращается положительное значение:

при успешном выполнении select () и pselect() возвращают количество файловых дескрипторов, содержащихся в трех возвращаемых наборах дескрипторов (то есть общее количество битов, установленных в readfds, writefds, exceptfds), которое может быть равно нулю, если тайм-аут истекает до того, как что-либо интересное происходит.

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

другой способ установить тайм-аут на без использования select() использовать setsockopt() для установки сокета SO_RCVTIMEO опция (на платформах, которые ее поддерживают).

в Windows код будет выглядеть следующим образом:

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)
        //...
}

на других платформах, код будет выглядеть следующим образом:

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))
        //...
}

используйте макрос FD_ISSET (), чтобы проверить, есть ли данные для чтения. Если он возвращает false, не выполняйте чтение.

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