Linux: есть ли чтение или recv из сокета с таймаутом?


Как я могу попытаться прочитать данные из сокета с таймаутом? Я знаю, select, pselect, poll, имеет поле timeout, но использование их отключает "tcp fast-path" в стеке tcp reno.

единственная идея у меня заключается в использовании приема(ФД ..., MSG_DONTWAIT) в цикле

5 84

5 ответов:

можно использовать setsockopt функция для установки таймаута на прием операций:

SO_RCVTIMEO

задает значение времени ожидания, которое указывает максимальное количество времени ввода функция ждет, пока она не завершится. Оно принимает временную структуру с помощью количество секунд и микросекунд указание предельного срока для ждать операции ввода полный. Если операция приема имеет заблокирован для столько времени без получая дополнительные данные, он должен: возвращение с частичным графом или ошибки установите значение [EAGAIN] или [EWOULDBLOCK] , если нет полученные данные. По умолчанию для этого параметр равен нулю, что указывает на то, что прием операция не должна тайм-аут. Этот параметр принимает временную структуру. Обратите внимание, что не все реализации разрешить установку этого параметра.

// 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);

на Windows, это должно быть сделано перед вызовом bind. У меня есть проверено экспериментально, что это можно сделать либо до, либо после bind на Linux и OS X.

вот простой код, чтобы добавить тайм-аут к вашей функции recv с помощью опроса в 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;
}

установите обработчик для SIGALRM, а затем использовать alarm() или ualarm() перед очередной блокировкой recv(). Если сработает сигнализация, то recv() вернет ошибку с errno значение EINTR.

// работает также после операции привязки для WINDOWS

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

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

Примечание: вы поставили эту настройку перед bind() вызов функции для правильного выполнения